Search code examples
c++game-physics

How to use deltaTime to produce consistent movement


I want to create a 2d game with velocity based movement. As the code currently is, I am using delta time to make the velocity changes consistent between framerates. When jumping, however, the jump height is very slightly different each jump (up to about 3 pixels difference with a maximum height of about 104 pixels) when running on a 144hz monitor, but when I switch to a 60hz, the jump height instantly increases by about 5 pixels average with a maximum height of about 109 pixels.

I have tried many different variations of what values I should normalise with delta time but I always come back to this one being the closest to the output I want.

static bool grounded = false;  

if (!grounded) {  
    velocity.y += (5000.0f * deltaTime);   //gravity  
}  

if (keys[SPACE_INPUT]) {       //jump command  
    if (grounded) {  
        position.y = 750;  
        velocity.y = -1000.0f;  
        grounded = false;  
    }   
}  

//Used to measure the max height of the jump  
static float maxheight = position.y;  

if (position.y < maxheight) {  
    maxheight = position.y;  
    std::cout << maxheight << std::endl;  
}

//if at the top of the screen  
if (position.y + (velocity.y * deltaTime) < 0) {  
    position.y = 0;  
    velocity.y = 0;  
    grounded = false;  

//if at the bottom of the screen minus sprite height  
} else if (position.y + (velocity.y * deltaTime) >= 800.0f - size.y) {  
    position.y = 800 - size.y;  
    velocity.y = 0;  
    grounded = true;  

//if inside the screen  
} else {  
    grounded = false;  
    position.y += (velocity.y * deltaTime);  
}  

I would expect the result to be that the sprite moves up the same height each time regardless of refresh rate but instead it moves up a varying amount, even on the same refresh rate and especially so between different rates.


Solution

  • The accepted technique is as follow:

    // this is in your mainloop, somewhere
    const int smallStep = 10;
    
    // deltaTime is a member or global, or anything that retains its value.
    deltaTime += (time elapsed since last frame); // the += is important
    
    while(deltaTime > smallStep)
    {
        RunPhysicsForTenMillis();
        deltaTime -= smallStep;
    }
    

    Basically, what you do is: each time you get to run your physics, you process a given number of steps of, say 10ms, that add up to the time between frames. The runPhysicsForTenMillis() function will do similar to what you have above, but for a constant delta time (10 ms is my suggestion).

    This gives you:

    • determinism. No matter your FPS, the physics will always run with the same exact steps.
    • robustness. Event if you have a long disk access, or some streaming delays, or anything that makes a frame longer, your objects won't jump into outer space.
    • online-play readiness. Once you go to online multi-player, you'll have to pick an approach. For many techniques like input-passing, the small steps will be significantly easier to make online.