19 March 2011

Code of the Ninja: Jump Height Calculator

If you haven't already, read the Code of the Ninja: Introduction

Hello again, Code Ninjas!

Today is something very simple: a formula that allows you to plug in variables for "jump force" and "gravity" and get the maximum height of a jump as the result.

When designing platformers, tweaking the physics until they're just right is very important. Having a formula such as this will be useful for zeroing in on exactly what values constants like gravity should have.

Another use might be this: say you already have established physics, for instance because you're hacking a Sonic game. But you want to add a new object, such as a new kind of bumper or spring, that bounces Sonic exactly 5 times his height. Determining the force at which Sonic should be impelled by the object in order to achieve that height would be a snap using the following formula.

The simplest way to write the formula is this:

g = gravity;
f = jumpForce;
h = 0;
t = 0;
while ( f > 0 )
{
  h += f;
  f -= g;
  t += 1;
}
return h;

g is your gravity, and f is the jump force, which can be set to anything. In Sonic, for example, gravity is 0.21875pps (pixels per step) and the jump force is 6.5pps.

h is the height value we are trying to find out - the number of pixels the character will travel given the jump force f with gravity g. t is time, which is optional - it will be the number of steps it takes to reach the apex of the jump. Both h and t are initialised at 0.

Then we run a loop while f is greater than 0. In the loop, first f is added to h, then g is subtracted from f. This simulates the jump: the force acts upon the character's position, then the gravity acts upon the force. t is then incremented by 1 in order to count the time.

When the loop is finished, h will be the ultimate height of the jump.

Note that this code assumes your physics to handle similarly to Sonic's. In Sonic, because of the particulars of the original code, the jump force is added once to the character's position before gravity acts upon it. If this is not the case in your game, then the loop should be restructured accordingly; g should be subtracted from f before f is added to h.

Earlier I said "the simplest way" to write the formula. The truth is that this, while simple, is a rather brute force method. Depending on the strength of the jump force and gravity, the loop could run dozens of times. Yes, modern computers can handle this without breaking a sweat, and yes, you probably won't even be using the formula in a running game, anyway. But for the sake of mathematical beauty, we can find a better way that doesn't employ a loop.

So let's build this new formula piece by piece. First, we need to find how many steps it will take for gravity to whittle the jump force away to 0 (or less). This will be time t again.

g = gravity;
f = jumpForce;
t = ceil(f/g);

We find t by dividing f by g and rounding up to the nearest 1. Why the rounding up? Well, if the jump force isn't perfectly divisible by gravity, the remainder would still count as upward velocity and the player would still move up by a little bit during that step. Since it counts toward the total, it must be taken into account.

Now that we know how long the jump will take to reach the apex, we can easily discover the distance the character would travel during that time, without gravity, merely by multiplying f by t.

h = f*t;

Of course this seems a little silly, because we're trying to find the height covered with gravity taken into account. But knowing this value is useful; 'cos if we can also determine how much force is deducted by gravity from the jump force over t steps, we can multiply gravity by that number, subtract it from h, and have our correct result.

In the first step (t = 0), the jump force is unaffected. In the next, it is lesser by gravity. In the next, it is lesser by gravity again, i.e. it is equal to the initial jump force value minus gravity times two. Next step, times three, then in the next, times four, and so on, until gravity overcomes the jump force in step t-1.

Visually represented, you might think of the amount of force lost to gravity as a triangular stack like this:

----- (t=0)
g---- (t=1)
gg--- (t=2)
ggg-- (t=3)
gggg- (t=4)
ggggg (t=5)
...

Fortunately it is easy to find the area of a triangle such as this by finding the area of a square the size of t*t-1 and then cutting that value in half. (If, as mentioned above, your physics subtract gravity before the character moves once, the square should have a size of t*t+1 instead).

h -= t*(t-1)*0.5*g;

Et voilĂ , you have the correct height of the jump, identical to the result of the while statement method used above.

Finally, because multiplication is a commutative process, the formula can be recast in a simpler way for our final code:

g = gravity;
f = jumpForce;
t = ceil(f/g);
h = (f-((t-1)*0.5*g))*t;
return h;

You can find a small example .gmk here that lets you play with the variables to get different jump heights. Until next time, happy coding!

If you use my code or scripts in your game or engine, no credit is necessary. But I'd love to hear about your project if you do! Just drop me a comment below, or e-mail me at us.mercurysilver@gmail.com

No comments:

Post a Comment