On Jumping Physics in Games

In which I summon up the quadratic formula to battle a problem whose solution doesn’t seem to be on the internet yet

There’s a very common mechanic in action games where you can control how high you jump through how long you hold down the jump button. Back in the day Sonic the Hedgehog implemented this by directly twiddling the player’s velocity, but modern games built on a physics engine usually do something like this:

when jump is first pressed:
    apply an upward impulse J
for time T afterwards:
    if jump is still pressed, apply smaller upward force F

Typically you’d just tweak J and F until you’re happy with how the player is jumping.

The problem I ran into today is, I want to define the total height of the jump as a tunable parameter, and derive J and F such that the jump winds up being the desired height. That way I can have something like an “item that lets you jump 3 blocks higher than usual” without stopping to figure out what physics settings would make the jump work out that way.

To achieve this, we have to dust off some high school physics.

The initial impulse

When jump is first pressed we apply an impulse J, which should be strong enough to cause a jump of height h. If the button is immediately released no further forces will be applied, so h is the minumum height it’s possible to jump.

Deriving J is straightforward - we just note how much potential energy the player will have at the peak of the jump, and apply an impulse giving the same amount of kinetic energy. Assuming a player of mass m, under gravity g:

PE = mgh            // Potential energy at peak of jump
KE = mv²/2          // Kinetic energy at initial jump velocity v
mgh = mv²/2         // set them equal and solve for v
v² = 2gh
v = sqrt(2gh) 
J = mv              // Definition of impulse
J = m * sqrt(2gh)   // voilà!

The gradual force

Now the hard part. After the player jumps, we apply a force F over some time t (or until the button is released). We want to tune F such that, if applied for time t, the jump will reach a total height of H.

As before, we can note that at the peak of the total jump the body will have potential energy mgH, so the work W done by the gradual force must be that value minus the energy contributed by the initial impulse. However, work is force times distance, so we’ll need to define d as the distance the body moves while the force is applied, and then state d in known terms so it can cancel out of the equation.

Here goes:

PE = mgh            // Potential energy at peak of jump
E₁ = mgh            // Energy from initial impulse 
E₂ = mgH            // Potential energy after entire jump 
W = E₂ - E₁         // Work to be done by gradual force
W = mg(H-h)
W = Fd              // definition of work
d = W/F             // distance moved while force is applied
d = mg(H-h)/F       // (1)
d = vt + at²/2      // distance stated in terms of velocity/acceleration
                    // note v = sqrt(2gh), from above
a = F/m - g         // acceleration comes from jump force and gravity
d = vt + (F/m - g)t²/2
                    // combine (1) and the previous, canceling out d
mg(H-h)/F = vt + (F/m - g)t²/2

At this point F is defined purely in terms of known values - all that’s left is to solve for it. For clarity, define f = F/m

f = F/m
mg(H-h)/F = vt + (F/m - g)t²/2
g(H-h)/f = vt + (f - g)t²/2
g(H-h) = fvt + f(f - g)t²/2
2g(H-h) = 2fvt + f(f - g)t²
2g(H-h) = 2fvt + f²t² - gft²
0 = f²t² + f(2vt - gt²) - 2g(H-h)
                    // BOOM quadratic equation
f = (-b + sqrt(b²-4ac)) / 2a
    where:  a = t²
            b = 2vt - gt²
            c = -2g(H-h)
F = m (-b + sqrt(b²-4ac)) / 2a

Implementation

And there you have it! Below are my javascript implementations. In both cases, dist is the distance contributed by that part of the jump physics, so the total jump height will be the sum of the distances you pass to each function.

function getJumpImpulse(dist, g, mass) {
var v = Math.sqrt(2 * g * dist)
return mass * v
}

function getJumpForce(dist, g, mass, t) {
// t is the total time the jump force can be applied, in seconds
var v = Math.sqrt(2 * g * dist)
var a = t * t
var b = 2 * v * t - g * t * t
var c = - 2 * g * dist
return mass * (-b + Math.sqrt(b*b-4*a*c)) / (2*a)
}

Caveat

When plugged into an actual game, your character will jump a little bit lower than the equations predict, due to the physics being simulated in discrete timesteps. The size of the error will depend on how big your timesteps are.