Help in game development. Render loop?

I am working on a simple game, this is my first game project.

Most of the samples that I find have a Render Loop, where all the logic games are made too, and I just don't like it. Let them say that I have a ball with X = 0, and a wall in X = 10 and a slow machine, the first loop puts the ball in X = 7 and in the second loop puts the ball in X = 14. This will simply destroy the game!

Is this "rendering cycle" the right way to create games? Do I have to write code to test such things in every frame? For example, the new frame is X = 14, the last frame has X = 7, so I have to check if there is anything from X = 7 to X = 14 ??

I thought that I should have a separate thread for the game logic and in the rendering cycle, I should just "take a picture" of the current game logic and show what is not?

How did you guys experienced game developers get around this?

thanks!

+6
game-engine game-loop
source share
7 answers

As another answer said, the problem you see is called “tunneling”. The problem is "bullet through paper", the bullet is moving fast, the paper is thin, how do you know that a collision occurred?

Easy if your world borders are simple. For example. in Tetris, blocks are only allowed to move left and right until they fall to the sides, and it is easy to check whether the lowest coordinate is on the ground. These tests are simple because you can do one axis at a time, and collisions with the sides mean something other than collisions with the bottom of the pit. If you have a rectangular room, simply “stop” the moving object, if its movement has moved it outside the room, holding its coordinates. That is, if the width of the room is from -3 to +3, and your object has an X of 5, just change it to 3 and you are done.

If you want to handle more complex worlds, it's a little more complicated. You will want to read the “estimate” of the collision geometry. Basically, if you have a circle, you need to make a collision with the capsule instead, a shape that will be made by “sweeping” the circle from the start point to its end point. It will be like a rectangle with semicircles at both ends. Mathematics is surprisingly straightforward (IMHO), but it can be difficult to do it right and really understand what is happening. It's worth it!

Edit: In the problem with the thread - there is no need to complicate the situation. One thread is fine. Skipping update frames can also be confusing, and it's pretty advanced, since you really need to figure out the "future" and then interpolate all the interesting values ​​to this point. I do not call this a rendering cycle, since the rendering cycle is only part of the process.

def GameLoop(): while True: ReadInputs() FigureOutWhatStuffDoes() DrawItAll() 

Edit 2: This seems like an interesting discussion: http://www.gamedev.net/community/forums/topic.asp?topic_id=482397

+5
source share

If you create a separate thread for this, you also create a lot of complexity that you might not want to deal with. It is easily machined in one thread and one circuit.

Basically, what you want to do is have a loop that performs both logic and rendering, but not necessarily at each iteration. See this pseudo code:

 while(true) { oldTime = currentTime; currentTime = systemTime(); timeStep = currentTime - oldTime; // Only do logic x times / second if( currentTime > lastLogicTime + logicRefreshTime ){ doGameLogic( currentTime - lastLogicTime ); lastLogicTime = currentTime; } // Extrapolate all movements using timeStep renderGraphics( timeStep ); wait( screenRefreshTime ); } void doGameLogic( timeStep ) { // Update all objects for each( gameObject obj ) obj.move( timeStep ); } 

Let all solid movable objects inherit the SolidObject class. When you call SolidObject.move(timeStep) , this method checks how far the object can be moved within the given timeStep . If there is a wall in front of this point, then the object should stop, bounce and change direction, die or whatever.


Edit:

If two objects are moving, you can check if and where they collide. A lot of games are not very good, but here is how you do it:

First, compute the line of motion between oldTime and currentTime for each moving object. Then compare the lines to see if the two lines intersect. Please note: you need to consider the size of the objects. The intersection point is where the objects collide. Using this method, you can accurately detect collisions of moving objects.

+4
source share

You can create a separate update flow and draw-thread , but it is not easy! Usually you need to do a lot of mutex checking to prevent multithreaded access to the same variables so that it is not really viable (plus you do not want to process half of the updated states). For a proper implementation, you really need to have some kind of snapshot of the last visualization state. If you don't mind complexity, there is a good implementation that can be found here:

http://blog.slapware.eu/game-engine/programming/multithreaded-renderloop-part1/

http://blog.slapware.eu/game-engine/programming/multithreaded-renderloop-part2/

Do not let skeptics dissuade you. Perhaps it is viable and effective. The only drawback is that it is very difficult to implement and therefore probably not worth your time (unless you have a very hard game with a processor).

+3
source share

Do not insert it - you will cause more problems than you solve. You can perform threads and separate logical updates and rendering, but it is difficult to get the correct and large parts of the game loops, essentially single-threaded.

Instead, take a look at advancing your game loop using delta time to scale so that the logic update is largely independent of the machine’s ability to twitter through frames.

In simplified terms, if you use a delta to scale things, no matter how long it takes to go through the frame, a ball moving from one side of the room to the other will take the same amount of time to do this on a really fast PC and slow.

eg. If the ball moves 10 units in one second, and you can determine that 0.1 seconds have passed since the last update (use a high performance timer or something that is available to you), you simply scale the movement by 0.1, and the ball moves by 1 unit.

eg.

 private const float BallSpeedInMetresPerSecond = 10; public void Update(float deltaTimeInSeconds) { float adjustedSpeed = deltaTimeInSeconds * BallSpeedInMetresPerSecond; // set ball speed / move it etc. using adjusted speed } 

This will not completely solve your problem (if something is really fast, it will get stuck in the walls independently!), But it is a simple and effective way to keep things predictable and consistent until you run into more complex problems.

If you get this working, and then want to solve a more complex problem, as dash-tom-bang said, look at the expanded collision detection.

+2
source share

I thought I needed a split thread for the game logic and in the rendering cycle I should just “take a picture” of the current game logic and display, what?

There is no easy, safe and quick way to take a picture of a massive piece of the game state. You can double the buffer, which is probably the next best. But this still does not fix the problem, so no, you would not do this, at least not for this purpose.

Say I have a ball with X = 0 and a wall in X = 10 and in a slow machine, the first loop puts the ball in X = 7 and in the second loop it puts the ball in X = 14. This will simply destroy the game!

Threading the two will not solve this if you cannot guarantee that every computer that you used will always be fast enough to check X = 1, X = 2, X = 3 ... X = 10. You cannot do this guarantee. And even if you could, you could rarely use integers for positions. Can you iteratively check X = 0.0000001, X = 0.0000002, X = 0.0000003 ... X = 0.9999999, X = 10.00000? Not.

How did you guys experienced game developers get around this?

Usually we have one cycle. input, update, rendering, replay. The conflicts you are talking about are solved using the collision detection method, which calculates the area through which the object will pass, for example. resolving for X = [from 0 to 17]. On a very slow machine, it can be X = [0-50], and on a fast machine it can be X = [0-5], followed by X = [5-10], but each will work as expected.

+1
source share

From my limited experience in developing games and AI, I would say that you have a logical loop and a display loop (like XNA). The logical loop (update method in XNA) will mainly handle the update position and what not, while the display cycle (Draw method in XNA) will draw everything on the screen. As for collision detection, I would personally localize this on your ball. When he moves, he seeks a collision and reacts accordingly.

Threading is another topic, but in my opinion, I would say so as not to separate the update and draw. It just seems to me that I'm wrong to potentially have 2 draws for 1 update or vice versa. Why draw if nothing is updated ... or why update several times before showing the user what is happening.

Just my opinions, I hope that I'm not from the base.

0
source share

If logical updates are usually cheap, and rendering is occasionally expensive, the easiest way to decide is whether there will be N logical updates per second. N = 60 is common - but you just have to choose the lowest value that allows the game to work well, choose a value and adjust the game until it runs at that speed or (most likely) some combination of the two.

At runtime, keep track of the elapsed time, keep track of how much time has logically passed (in terms of the updates performed) and when there are more than 1.0 / N seconds of inconsistency (since rendering takes too much time) perform additional updates to catch up. This is better than trying to execute an arbitrary period of time for updates at a time, because it is more predictable. (If the reader does not agree, they may find this difficult.)

The disadvantage of this system is that if rendering becomes especially time-consuming and the logic needs to perform too many updates, because of this they may not synchronize a bit and the logic will never catch up. If you aim a fixed system, it just indicates that you are trying to do a lot, and you will have to do something less somehow or (if this situation is likely to be rare) just dump the whole idea and render: 1: 1. If you are targeting something variable, like on a Windows PC, you just need to pin down the number of content logical updates and hope that this allows things to get back to work.

(If logic is more expensive, this approach does not work, I never worked on a game if that was a problem.)

0
source share

All Articles