Canonical Game Loop

From Physics Simulation Wiki

Jump to: navigation, search

In order to get your application to exhibit total Framerate Independence, you need a main loop that can step the world by an amount appropriate to the time it needs, and render frames. Naive implementations of a game loop will typically run into a variety of problems, including framerate stuttering or fixed at a low figure, and/or physics behaviour changing based on framerate. Multiplayer networked games *must* exhibit framerate independence for players to get a good experience.

Important references:

Presented here is a simple canonical game loop that you can use in your Bullet-based game.

All times are measured in milliseconds, and timing is done through a hypothetical getMilliseconds() function which returns the rate monotonic time in milliseconds. It doesn't matter what the time is relative to, since we count relative to the value getMilliseconds() returned when we started. [Some systems might use the time since a process began, some systems might use time since the epoch, some systems might use the time since the system booted...]

Example Code

///TickMs is the amount of time that our internal fixed clock runs at, I use 32ms
/* This is not the same as the Bullet internal clock, but instead specific to our gameplay */
const unsigned int TickMs 32

/// The physics clock is just used to run the physics and runs asynchronously with the gameclock
unsigned long time_physics_prev, time_physics_curr;

/// There's an inner loop in here where things happen once every TickMs. These variables are for that.
unsigned long time_gameclock;

/// Reset all of our timers
time_physics_prev = time_physics_curr = getMilliseconds();
time_gameclock = getMilliseconds();


while (!done) {
    if(user_indicates_they_want_to_quit) {
        done = true;
    }

    // Render a frame
    if(false == video->renderOneFrame()) {
        done = true;
        // Game quits if render failed
    }

    // Physics handling part of the loop
    /* This, like the rendering, ticks every time around.
    Bullet does the interpolation for us. */

    time_physics_curr = getMilliseconds();

    // Tick the bullet world. Keep in mind that bullet takes seconds, and we measure time in milliseconds.
    mWorld->stepSimulation(((float)(time_physics_curr - time_physics_prev))/1000.0, 10);

    time_physics_prev = time_physics_curr;


    // Game Clock part of the loop
    /*  This ticks once every TickMs milliseconds on average */
    long long dt = getMilliseconds() - time_gameclock;

    while(dt >= TickMs) {
        dt -= TickMs;
        time_gameclock += TickMs;

        // Pulse the input every TickMs milliseconds
        input->do_all_your_input_processing();

        // Everything on your system that needs to happen once every game tick should be processed here
        TWTickable::tickAll(TickMs);
    }
}
Personal tools