Search code examples
c++timegravitydelta

How do I keep the jump height the same when using delta time?


I'm using delta time so I can make my program frame rate independent. However I can't get the jump height it be the same, the character always jumps higher on a lower frame rate.

Variables:

const float gravity = 0.0000000014f;
const float jumpVel = 0.00000046f;
const float terminalVel = 0.05f;
bool readyToJump = false;
float verticalVel = 0.00f;

Logic code:

if(input.isKeyDown(sf::Keyboard::Space)){
    if(readyToJump){
        verticalVel = -jumpVel * delta;
        readyToJump = false;
    }
}

verticalVel += gravity * delta;
y += verticalVel * delta;

I'm sure the delta time is correct because the character moves horizontally fine.

How do I get my character to jump the same no matter the frame rate?


Solution

  • The formula for calculating the new position is:

    position = initial_position + velocity * time
    

    Taking into account gravity which reduces the velocity according to the function:

    velocity = initial_velocity + (gravity^2 * time)
    

    NOTE: gravity in this case is not the same as the gravity. The final formula then becomes:

    position = initial_position + (initial_velocity + (gravity^2 * time) * time
    

    As you see from the above equation, initial_position and initial_velocity is not affected by time. But in your case you actually set the initial velocity equal to -jumpVelocity * delta.

    The lower the frame rate, the larger the value of delta will be, and therefore the character will jump higher. The solution is to change

    if(readyToJump){
        verticalVel = -jumpVel * delta;
        readyToJump = false;
    }
    

    to

    if(readyToJump){
        verticalVel = -jumpVel;
        readyToJump = false;
    }
    

    EDIT:

    The above should give a pretty good estimation, but it is not entirely correct. Assuming that p(t) is the position (in this case height) after time t, then the velocity given by v(t) = p'(t)', and the acceleration is given bya(t) = v'(t) = p''(t)`. Since we know that the acceleration is constant; ie gravity, we get the following:

    a(t) = g
    v(t) = v0 + g*t
    p(t) = p0 + v0*t + 1/2*g*t^2
    

    If we now calculate p(t+delta)-p(t), ie the change in position from one instance in time to another we get the following:

    p(t+delta)-p(t) = p0 + v0*(t+delta) + 1/2*g*(t+delta)^2 - (p0 + v0*t + 1/2*g*t^2)
                    = v0*delta + 1/2*g*delta^2 + g*delta*t
    

    The original code does not take into account the squaring of delta or the extra term g*delta*t*. A more accurate approach would be to store the increase in delta and then use the formula for p(t) given above.

    Sample code:

    const float gravity = 0.0000000014f;
    const float jumpVel = 0.00000046f;
    const float limit = ...; // limit for when to stop jumping
    
    bool isJumping = false;
    float jumpTime;
    
    if(input.isKeyDown(sf::Keyboard::Space)){
        if(!isJumping){
            jumpTime = 0;
            isJumping = true;
        }
        else {
            jumpTime += delta;
            y = -jumpVel*jumpTime + gravity*sqr(jumpTime);
            // stop jump
            if(y<=0.0f) {
                y = 0.0f;
                isJumping = false;
            }
        }
    }
    

    NOTE: I have not compiled or tested the code above.