4
\$\begingroup\$

I have a procedural approach to the game loop that runs various classes.

it looks like this:

  1. continue any in progress animations
  2. check for used input
  3. apply AI
  4. move things
  5. resolve events such as collisions
  6. draw it all to screen

I have seen a lot of posts about how drawing should be running separately as fast as it can, possibly in another thread.

My problem is that if the drawing runs as fast as it, can what happens if it tried to draw while I'm still applying the AI or resolving a collision? It could draw the wrong thing on screen.

This seems to be a well established idea so there must be an explanation to this problem as I just cant get my head around it. The only solution I have is to update the screen so fast that any errors like that get refreshed before we see them but that sounds hacky.

So how does this work / how would you implement it so that they are in sync but running at different speeds?

\$\endgroup\$
2
  • 2
    \$\begingroup\$ The accepted answer to this question may help. \$\endgroup\$ Commented Jun 16, 2011 at 14:44
  • \$\begingroup\$ Remember you are talking about fractions of a second. If its 'wrong' its wrong by 0.016 or a second or so, and it will be corrected in 0.016 of a second, hehe. \$\endgroup\$
    – James
    Commented Jun 16, 2011 at 17:19

3 Answers 3

0
\$\begingroup\$

This link, suggested by 3nixios, addresses what you're talking about.

The issue that's holding you back is concurrency (threading) and locking, and being aware of that it can be a problem is half the battle.

I suggest reading the accepted answer to the link, but the short version is that you will only draw or update the unlocked items, but before you do you'll ask the program to lock the object/variable. After you are done with it, you'll unlock it.

The wikipedia article on this isn't a bad starting point. http://en.wikipedia.org/wiki/Lock_(computer_science)

There are issues around lock contention and dead locks and such, but any good concurrency reference will discuss these in gory detail.

Hope this helps.

\$\endgroup\$
1
\$\begingroup\$

Edit: Since some people got a bit confused as to what I meant, I'm going to elaborate a bit.

This is called a race condition. You don't go into a lot of detail as to how your game works, but here is what I can offer:

  • If you can draw the data-dependent stuff onto a reasonably-sized surface, you can draw once, then keep the surface, and draw it onto the screen while processing. This way you can redraw cursor, HUD, etc onto the screen, but not ruin the game image, since you have it as a separate surface. Edit: So the procedure would now be: render onto work_in_progress_surface and blit last_stable_surface onto the screen, until you are done with AI and moving things. Now blit work_in_progress_surface onto last_stable surface and clear it for the next frame. Get user input and repeat. The main idea here is that you keep the last good frame separated.
  • You can save the new data in an alternate memory space. Once everything is calculated, just point to the new data and deallocate the old. You might want to / have to split game data into two parts: screen-changers and behind-the-scenes data. Or flag it, however you like. Edit: One possible way to implement this is to make a list of all objects that could change in mid-render. Before applying AI and moving things make a deep copy of everything listed, render the old data but modify the new data. When your AI/moving is finished, just deep copy all new data into the normal objects.
  • If the AI/moving is guaranteed to be very fast - less than ~200ms where it doesn't bother users, you could just suspend rendering and the UI through a semaphore. Set it to 0 when the renderer is running, then have the AI/moving set it to 1 and wait, when the renderer finishes, it should look at it before starting again. When it sees the 1 it will set it to 2 and stop rendering. The AI/moving will see the 2 and start working. When all render data has been modified, the AI/moving sets it back to 0 and backgrounds. The render thread sees the 0 and resumes rendering. This is how a pretty simple semaphore works, don't skip the extra transitional phase, think about why it's there.
\$\endgroup\$
6
  • \$\begingroup\$ -1 doesnt answer the sync question at all, not even mentioned threads \$\endgroup\$ Commented Jun 16, 2011 at 19:36
  • \$\begingroup\$ +1 because the answer is clearly pointing out using double buffering between threads. \$\endgroup\$ Commented Jun 17, 2011 at 1:46
  • \$\begingroup\$ @Daniel A double buffer does not solve the problem in this particular case, it only solves the problem if render-thread and game-thread run in sync already (with the same fps), so the render-thread renders last frame's game (front-)buffer, game thread manipulating current game (back-)buffer, but even then the renderers already have such a double buffer so there is no point in introducing a new one here. \$\endgroup\$ Commented Jun 17, 2011 at 10:41
  • \$\begingroup\$ @Daniel the problem described in the question, however, is different, the rendering thread runs faster as the game-thread, so it would either outpace the double-buffer after some frames leaving you with the original sync problem, or it has to render the same buffer more than once, which invalidates the whole point of having the rendering thread running faster. Long story short, the double buffer does not solve the problem in OP's described scenario. \$\endgroup\$ Commented Jun 17, 2011 at 10:43
  • 1
    \$\begingroup\$ Ignore the last part of my first post talking about renderer's double-buffer, that was nonsense, the main point stands anyway ;) \$\endgroup\$ Commented Jun 17, 2011 at 10:58
1
\$\begingroup\$

I have seen a lot of posts about how drawing should be running separately as fast as it can, possibly in another thread.

This is an outdated view of parallelism in game engines. A more modern view would, instead of running simulation and rendering in parallel, parallelise the simulation and rendering separately.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .