Platformer Physics 101 and The 3 Fundamental Equations of Platformers

There are tons of tutorials out there on doing platformer physics and implementing various types of platformers.  What there seems to be lacking is a tutorial on how to choose good values for your platformer physics. This article will present some core physics equations in a new light!  I will even be so bold as to christen these equations as The Fundamental Equations of Platformers.  The sample code here is presented in LUA and for my prototyping I am using the ShiVa 3D game engine.

When designing physics for a platformer, the 2 fundamental values required are:

  1. The strength of gravity
  2. The initial velocity of a jump

With these values, we’re able to use the the kinematic equations to make a character jump and eventually touch the ground again.

Basic Physics

3/22/2014 Please see comment by Ricky below. These simple equations are the calculus versions broken down for simplicity, not the kinematic equations.

As a refresher, the 2 basic equations we’ll use are:

velocity=acceleration\cdot time
distance=velocity\cdot time 

This would be a typical implementation.

-- Set Y velocity to the jump velocity
this.nVelocityY( this.kVelocityJump )
-- Apply gravity every frame
local dt = application.getLastFrameTime( )
local newVelocityY = this.nVelocityY( ) - this.kGravity( ) * dt
local distanceToMoveY = newVelocityY * dt

-- Assuming collision detection was ok, move the actor
object.translate( this.getObject( ), 0, distanceToMoveY, 0, object.kGlobalSpace )
this.nVelocityY( newVelocityY )

This code is at the heart of platformer physics, but when it comes down to it, these equations alone kind of suck at being useful. Picking random values isn’t the best way to get a good feeling platformer. Let’s look at a method that will help get you started with initial physics values.

The Fundamental Equations of Platformers

What makes more sense is to calculate gravity and initial jump velocity by picking 2 simple properties of the universe:

  1. Max jump height
  2. Time to reach max height

Which leads us to the first two fundamental equations:

gravity=\dfrac{2\cdot height_{MaxJump}}{time_{ToApex}^2}\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;(1) 
V_{jump}=\sqrt{2\cdot gravity\cdot height_{MaxJump}}\;\;\;\;\;\;(2)

So what we’ve defined above are:

  • gravity as a function of the time to reach the top of the jump and maximum jump height.
  • initial jump velocity as a function of gravity and maximum jump height

The Derivations

Equation 1

Assuming that we are standing on the ground preparing to jump, we start with the kinematic equation d=v_it + \dfrac{1}{2}at^2

Setting initial velocity to zero d=\dfrac{1}{2}at^2

Solving for a yields a=\dfrac{2d}{t^2}

Equation 2

Assuming that we are standing on the ground preparing to jump, we start with the kinematic equation v_f^2=v_i^2+2ad

Setting initial velocity to zero v_f^2=2ad

Solving for v yields v_f=\sqrt{2ad}

Early Jump Termination

Edited 3/5/2014

As reader Chue points out, the equations below don’t work unless gravity is negative. This is true and was an oversight on my part. You could redefine the above equation for gravity and just tack a negative sign on it. This also means that the equation for jump velocity is going to yield an imaginary number (square root of a negative number), you can just throw that imaginary part away. I’ve updated the equations below to show that gravity is being plugged in as a negative number.

The end numbers haven’t changed, I just failed to show my work. The spreadsheet at the end of the article was not affected.

There are a few ways to do early jump termination but I am going to propose a method that is based on a single parameter, minimum desired jump height.  The idea is to calculate the downward velocity required to achieve this minimum height. I now present the 3rd fundamental platformer equation (which is a well known kinematic equation):

V_{EarlyJumpTermination}=\sqrt{V_{jump}^2 + 2\cdot gravity (height_{MaxJump} - height_{MinJump})}\;\;(3)

To use this, we choose our minimum jump height of 1 unit and we arrive at:

V_{EarlyJumpTermination}=\sqrt{16^2 + 2\cdot -32 (4 - 1)} = 8

So then in code, when a player releases the jump key, you’d do the following:

if( this.nVelocityY ( ) > 0 ) then
    -- Set velocity to whatever is smaller, termination velocity or current velocity
    this.nVelocityY ( math.min ( this.kJumpVelocityTermination ( ), this.nVelocityY ( ) ) )
end

The one caveat with this method is that, depending on your world, you may set a minimum jump height that is impossible for a human to hit. Because obviously we have limitations, like not being able to press and release a key much faster than 200 milliseconds. So, as a friendly check, we can calculate the last possible second that a jump can be terminated using this equation:

t=time_{ToApex} - \dfrac{2(height_{MaxJump} - height_{MinJump})}{V_{jump}+V_{EarlyJumpTermination}}

Demo

To prove out the equations and method, I did my best to recreate the physics from Mario 1 inside the ShiVa 3D game engine.  Based on my reverse engineering efforts (see details below) I arrived at the following values: * Max Jump Height = 4 units * Time to reach max height = 0.44 seconds * Minimum jump height = 1 unit

So plugging these into equations 1, 2 and 3 we get gravity=\dfrac{2\cdot 4}{0.44^2} = 41.322

V_{jump}=\sqrt{2\cdot 41.322\cdot 4}=18.182

V_{EarlyJumpTermination}=\sqrt{18.182^2 + 2\cdot -41.322 (4 - 1)}=9.091

Now see it in action, spacebar jumps. Well, not anymore since chrome doesn’t let us embed stuff like this anymore :( See the Platformer Physics shiva example on my github.

How I measured Mario Gravity

Starting with Nestopia, I recorded a video of mario jumping.  I then saved that out as an AVI with uncompressed frames.  After pulling that into VLC Media Player, I used the scene filter to save out every frame of the video to a png.

The video was recorded at 50 frames/second which was a bit overkill, but this gave me 0.02 sec/frame.

Instead of counting everything in pixels or trying to convert to meters.  I decided to use units of game height.  In Mario, every object is based on a square of 16x16 pixels.  So I called this a game unit. Using photoshop, I overlaid a grid to display individual pixels. Notice that mario sits 1 pixel into the ground.

Mario Units

I then proceeded to make some basic measurements.  The time to reach the apex of a jump occurred in 22 frames * (0.02 sec/frame) = 0.44 sec

The total height traveled in a jump was 64 px / 16 = 4 units

It was a head scratcher to first determine how to measure the jump distance of mario based on how his animation changes when he jumps.  I decided to measure using the bottom of mario’s feet when standing and the bottom of his lower foot when jumping.  This is because when standing, mario’s feet extend 1 pixel into the terrain and while jumping, his bottom foot has a 1 pixel toe that at the highest jump point will extend 1 pixel into any reachable obstacle.

So then the gravity for mario is 2h / t^2 = 41.32 units/s^2

And then initial jump velocity is sqrt(2gh) == sqrt(241.324) == 18.182

I thought I’d look up the values for Mario’s gravity and see if perhaps I could compare my measurements.  I was excited when I found Acceleration Due to Gravity: Super Mario Brothers until I saw their measurement of the height of mario to be 39 pixels.  Perhaps this could have been due to over or underscan on their TV?  I mean, this value isn’t even a power of 2.  Mario is 1616 small and 1632 with a mushroom, everyone knows that!

Conclusion

This method may not match the exact jump model that mario uses, but as an approximation, I think it works very well. I’ve created a Google Docs template with the above equations built-in. Feel free to make a copy of it to calculate some starting values for your own platformer. Also if you’ve used the above method or see an issue with implications of the early jump termination method, please leave a comment!

Published 23 October 2013
blog comments powered by Disqus ~