A platform game character's gotta jump, right? Let's take a look at some different ways of implementing a jump. We already kind of did this in the forces and impulses topic, but now we'll think about how each method would fit into a game. Start with the same scene as for the moving at constant speed topic, with the fenced in area and the left/right controls to move a dynamic body.
Setting the velocity directly
When the player character jumps their velocity changes, so let's try doing that to start with. Add a case to handle jump input:
// When jump key is pressed
if (jumpKeyPressed) {
const vel = b2Body_GetLinearVelocity(bodyId);
vel.y = 10; // upwards - don't change x velocity
b2Body_SetLinearVelocity(bodyId, vel);
}
Now pressing the jump key will directly set the velocity, which as we know by now is not a physically realistic method. There are a few things to notice about this method that might make it unsuitable for a jump in a platform game. The momentum of the body is not taken into account, so the player can jump with equal strength even when they are falling quickly. The player can also jump in mid-air - however this might be what you want, say for a 'double-jump' feature. For now we'll settle for this jumping in mid-air, and in a later topic we'll look at how to determine when the player is standing on the ground or not.
Using a force
When you jump in real life, you are applying a force upwards on your body, so let's see if we can do that by using a strong force for a few timesteps. We'll need to keep track of how many more time steps the force should be applied:
// Module-level variable
let remainingJumpSteps = 0;
// When jump key is pressed
if (jumpKeyPressed) {
remainingJumpSteps = 6; // 1/10th of a second at 60Hz
}
// In step/update function
if (remainingJumpSteps > 0) {
b2Body_ApplyForceToCenter(bodyId, new b2Vec2(0, 500), true);
remainingJumpSteps--;
}
Now when jumping, the behaviour is similar to before, but this time when the body is falling, jumping has less effect since the existing downward momentum is taken into account. The magnitude used for the force here is just a number that seemed about right. If you want to specify the take-off velocity though, you could use the same formula as for finding forces to move the body left/right at a desired velocity (f=mv/t), and apply it evenly across all time steps:
if (remainingJumpSteps > 0) {
// to change velocity by 10 in one time step
const mass = b2Body_GetMass(bodyId);
let force = mass * 10 / (1/60.0); // f = mv/t
// spread this over 6 time steps
force /= 6.0;
b2Body_ApplyForceToCenter(bodyId, new b2Vec2(0, force), true);
remainingJumpSteps--;
}
Using an impulse
This is probably what you want in most cases, essentially the same force as above but applied in only one time step to take full effect instantly. As in the previous topics we can just leave out the time component:
// When jump key is pressed
if (jumpKeyPressed) {
// to change velocity by 10
const mass = b2Body_GetMass(bodyId);
const impulse = mass * 10;
b2Body_ApplyLinearImpulseToCenter(bodyId, new b2Vec2(0, impulse), true);
}
This gives a behaviour closer to direct setting of the velocity than the force does, because each time step the force is applied, gravity gets a chance to push back. If you look closely you'll see that the forced jump does not quite go as high as the others. However if you have a situation where you want the jump to look a little softer, instead of like the character has been hit from below by a giant hammer, the force method might be useful.
Other methods
In real life, for every action there is an equal and opposite reaction. If you use your legs to push your body up into a jump, whatever you were standing on just got pushed down upon with an equal force. None of the methods above take this into account, and most likely in your game they don't need to. But if you wanted to have this modeled accurately, there are two ways you could do it, both of which we need some more study in order to implement so I'll just mention them in passing for now.
After first making sure that the player is standing on something, you could then apply the same force/impulse to that object if it's a dynamic body. This would look better when you are jumping on a swing bridge, for example, the bridge would get a realistic kick downwards as the player jumps instead of merely having the player's weight removed. For this we'll need to know how to tell what the player is touching.
Using a prismatic (sliding) joint to join two bodies together is probably the most accurate way to model a character jumping. In this method the player would have a main body like we are using here, and another smaller body joined to it which can slide vertically. The joint motor could be used to shove this smaller body downwards, much like you shove your legs downwards to jump. This has the nice advantage that we don't need to bother checking if the player is standing on anything because if it's not, pushing the 'legs' downward will just do nothing. We also get an opposite force applied downwards to whatever was under the player eg. to kick the swing bridge downwards. Furthermore, if the player is standing on something 'soft' like a swing bridge, the jump will be less effective, just like real-life. Of course apart from being more work to implement, this approach has it's own issues to consider. I hope to discuss this method in another topic after we've covered joints and joint motors.
Stopping the body from rotating
You've probably noticed the body is still freely rotating which is starting to feel a bit out of place now that we are starting to look at the body as a player character. The recommended way to stop this is simply to set the body as a fixed rotation body:
b2Body_SetFixedRotation(bodyId, true);
Credits
This tutorial is adapted from an original piece of work created by Chris Campbell and is used under license.