Box2D C++ tutorials - Jumping
Last edited: July 14 2013Chinese version -> 中文
Jumping
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 the Keyboard() function to get a jump input from the user:
1 2 3 4 5 6 7 | case 'j': //jump { b2Vec2 vel = body->GetLinearVelocity(); vel.y = 10;//upwards - don't change x velocity body->SetLinearVelocity( vel ); } break; |
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. In the Keyboard() function we will simply make a note that the jump was started, and apply the force in the Step() function. Use a class member variable to keep track of how many more time steps the force should be applied:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //class member variable int remainingJumpSteps; //in constructor remainingJumpSteps = 0; //keyboard function case 'k': //jump remainingJumpSteps = 6;// 1/10th of a second at 60Hz break; //in Step() function if ( remainingJumpSteps > 0 ) { body->ApplyForce( b2Vec2(0,500), body->GetWorldCenter() ); remainingJumpSteps--; } |
1 2 3 4 5 6 7 8 | if ( remainingJumpSteps > 0 ) { //to change velocity by 10 in one time step float force = body->GetMass() * 10 / (1/60.0); //f = mv/t //spread this over 6 time steps force /= 6.0; body->ApplyForce( b2Vec2(0,force), body->GetWorldCenter() ); 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:
1 2 3 4 5 6 7 | case 'l': { //to change velocity by 10 float impulse = body->GetMass() * 10; body->ApplyLinearImpulse( b2Vec2(0,impulse), body->GetWorldCenter() ); } break; |
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:
1 | body->SetFixedRotation(true); |