Search code examples
c++cgame-enginegame-loop

Why use integration for a fixed timestep game loop? (Gaffer on Games)


http://gafferongames.com/game-physics/fix-your-timestep/

http://www.koonsolo.com/news/dewitters-gameloop/

In the last game loop from Glenn Fiedler's Fix Your Timestep! article, he uses an update loop that advances the game logic by a fixed delta time. Since the delta time is fixed, why does he integrate based on delta time? In a fixed timestep based game, can't movement be as simple as:

if ( keyboard pressing "W" ) {
    velocity += acceleration
}
position += velocity

instead of passing in a delta time varaible:

if ( keyboard pressing "W" ) {
    velocity += integrated(acceleration, delta_time)
}
position += velocity * delta_time

Because delta time in a "fixed" timestep loop has no purpose, it would be like multiplying everything by 1. In a "variable" timestep based game you would have to use delta time and integrate for motion but in this case it would not matter. Notice how the variable for delta time is set to a constant and never changed, the game logic is already deterministic and it doesn't seem like you need to multiply velocity and acceleration by delta time anywhere in the code. What I took away from the article was "Fix Your Timestep!," as the name implies, so you have deterministic game logic instead of floating point inaccuracies and exploding physics that come with variable timesteps. I was just confused over why delta time was being passed into the update function since it seems to go against the purpose of the article. Both articles in fact make the same argument against delta time.

double t = 0.0;
double dt = 0.01;

double currentTime = hires_time_in_seconds();
double accumulator = 0.0;

State previous;
State current;

while ( !quit )
{
    double newTime = time();
    double frameTime = newTime - currentTime;
    if ( frameTime > 0.25 )
        frameTime = 0.25;
    currentTime = newTime;

    accumulator += frameTime;

    while ( accumulator >= dt )
    {
        previousState = currentState;
        integrate( currentState, t, dt ); // integration
        t += dt;
        accumulator -= dt;
    }

    const double alpha = accumulator / dt;

    State state = currentState * alpha + 
    previousState * ( 1.0 - alpha );

    render( state );
}

deWiTTERS last game loop does the same thing: fixed timestep, interpolate rendering, render skipping. However it does not mention integration like the other one.


Solution

  • Assuming that acceleration increases or decreases linearly versus time, you could base velocity change on average acceleration

    Δv = (a0 + a1)(Δt)/2
    

    If the game includes factors like aerodynamic drag, then acceleration is affected by velocity^2, and usually something like Runge Kutta 4 is used to update velocity change and position change for each time step.


    My impression is that most PC based games use an independent fixed frequency for the physics engine that is ideally independent of frame rate. For these games, even if the display is sluggish the actual game play is the same if the player can deal with the visuals. I've seen older racing games that get this right, where graphics performance doesn't affect the physics, and newer racing games where lowering graphics settings improves the in game car performance, which is a bug.

    Link to example Windows code for running a thread at just about any reasonable fixed frequency, with no drift over time.

    16.66ms frames times. How do you get a perfect 60 fps when sleep() only goes by whole milliseconds?

    In the days of MSDOS, since a PC runs the timer at (105/88) Mhz = 1.19318 Mhz, games use it as a high precision timer counter.