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:
- The strength of gravity
- 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:
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:
- Max jump height
- Time to reach max height
Which leads us to the first two fundamental equations:
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
Setting initial velocity to zero
Solving for a yields
Equation 2
Assuming that we are standing on the ground preparing to jump, we start with the kinematic equation
Setting initial velocity to zero
Solving for v yields
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):
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:
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
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 16×16 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.
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!
Be the first to comment