Timing game loop

Started by
9 comments, last by Aardvajk 10 years, 2 months ago

Here's the fundamental thing to bear in mind - you can never, ever predict the frame rate on any other machine than the one you are on.

If you use vsync to control the frame rate, you're code will be run on a machine with a different refresh rate, or someone will force vsync off on their graphics card settings (causing the hardware to falsly report vertical blank period as soon as it is asked rather than when it is actually happening).

The Fix Your Timestep article has already been posted. This is the defacto standard article to read on this subject. Fix your timestep and allow your graphics to render as fast as possible. Make vsync optional and never assume it is on even if you have requested it in your setup.

You pass a delta value into your update() methods and move based on this. So if your object should move 10 units per second, you add 10 * delta to the position where delta is a float representing the number of seconds (normally a small value like 0.0016) that have passed since the last update.

The gaffer article, in my humble option, makes it seem a bit more complicated than it actually is. I've found all you need to store is the previous position and the current position, then interpolate between them based on the error. My game loop looks something like:


        float t = timer.elapsed();

        accumulator += t;

        while(accumulator >= delta)
        {
            app.update(delta);
            accumulator -= delta;
        }

        app.render(accumulator / delta);

I use a fixed delta (1.0f / 60.0f for example) so every update is deterministic and repeatable, and characters don't, for example, jump to different heights depending on the frame rate. This is a problem even with simple physics if you have variable timestep, not just highly sophisticated physics sims, although in the latter the problem can lead to worse consequences than characters jumping to different heights. Still, in a Mario style 2D platformer, you want complete control of the maximum jump height for obvious reasons. This approach is the way to ensure that on different hardware.

Each entity stores previous and current position, then I do a linear interpolation based on the blend factor passed to app.render when working out where to draw the entity. This means the visuals always lag very slightly behind the real game state, but that's fine.

You also need to store previous values for things like fade values, animation track positions and so on and interpolate these but I've never found it necessary to store and interpolate things like acceleration. Maybe its just too small a difference to be visually noticeable, or maybe I misunderstand Gaffer's article.

This approach is the most stable for physics, the most consistent across different hardware and very hard to find a reason not to do since it isn't really much work.

This topic is closed to new replies.

Advertisement