A simple jump
by Malte Skarupke
Here at DigiPen people make a lot of platformers. And I see them getting the basic jump wrong over and over again.
It turns out that you can write a whole lot about the implementation of jumps in games (ideal jump height and speed, amount of air control, double jumps etc.) but in this post I’ll just explain how to start a jump, because this is where I see people repeating the same mistake: If you have stepped just one pixel too far over the edge of the platform before pressing space, you will fall to your death.
Fixing that is fairly simple.
The trivial implementation of a jump looks something like this:
bool Jump::isOnFloor() const { return onFloor; } void Jump::onKeyDown(KeyboardMessage & msg) { if (msg.getKey() == ' ' && isOnFloor()) { getOwner()->getBody()->velocity.y = 10; } } void Jump::update(float dt) { onFloor = false; } void Jump::onCollision(Entity & owner, CollisionMessage & msg) { if(msg.getCollision().getNormal().y < -0.7) { onFloor = true; } }
So just keep track of a boolean that tells me whether I can jump now. Each frame it gets set to false, except if I’m colliding with the floor in that frame.
The problem is, that if I’m running and stepping over the edge of the platform by just one pixel, I can no longer jump. Which is pretty frustrating.
In my opinion the cleanest solution to that is this:
bool Jump::isOnFloor() const { return (getTime() - lastOnFloor).asSeconds() < 0.25f; } void Jump::onKeyDown(KeyboardMessage & msg) { if (msg.getKey() == ' ' && isOnFloor() && (getTime() - lastJump).asSeconds() < 0.25f) { lastJump = getTime(); getOwner()->getBody()->getVelocity().y = 10; } } void Jump::onCollision(Entity & owner, CollisionMessage & msg) { if(msg.getCollision().getNormal().y < -0.7) { lastOnFloor = getTime(); } }
The function getTime() returns the current time. In my case this returns a struct with seconds and microSeconds. The function asSeconds() returns how long the given timeSpan is in seconds. (as a float)
Instead of the boolean, we now keep track of the time when we last collided with the floor. If my last collision with the floor was less than 0.25 seconds ago, then I can jump.
In most cases this does exactly the same as the first implementation. Except that if I have stepped over the edge of a platform just a very short time ago, I can still jump. Same thing for moving platforms that have just barely slipped out from below me.
If you think that the first implementation is more “correct,” then consider that the visuals on screen probably don’t agree 100% with your physics system’s interpretation. In fact I have found that the second implementation feels more correct in the game. The tolerance time is so short that your character is likely to be still right next to the platform, so obviously he could still push himself up from it.
Use this technique, and I guarantee that your jumps will just feel better.
(Picture from Dino Run. A platformer that I happen to enjoy a lot at the moment.)