Platforming Ledge Forgiveness
When it comes to making a cool platforming game there's all kinds of little tricks you can do to make your game shine above all the rest. I mentioned jump input buffering in a previous post and how silently helping the player out here and there can make a huge difference in the feel of your game. The topic of this post is very similar to that!
Take a look at this typical platforming scenario. Our player is barreling toward a ledge at top speed, just holding right without a care in the world. They're going to want to jump when they get to the end of that ledge, and they're probably going to want to hit jump as late as possible so that they get the maximum distance out of their jump.
Ideally they would hit the jump button right now. Their character is still on the ground, and in the most simple implementation of a platformer jump system then this would be fine. I assume that the code would be just something along the lines of if (onGround) { jump(); } and onGround would evaluate to true if our player collides with the ground at y + 1.
But what happens if the player just slightly overshoots the ledge?
If our most basic platforming system is only looking at the player's y + 1 to detect the ground, then the player will not be able to jump in this case. At this point you might ask well doesn't that make sense? The player isn't on the ground, so they can't jump... that's how it would work in the real world!
This isn't the real world though, this is video games! If you're playing a fast paced platformer running at 60 frames per second, it's incredibly easy to hit the jump button right after you run off a ledge, but to your feeble human eyes it looked like you hit the jump button while you were still on the ground. This can be incredibly frustrating, especially if you're trying to make jumps across some pretty wide gaps and you're trying to maximize your jump distance.
What I like to do for my games for this situation is to introduce a timer that keeps track of how long it has been since the player last touched the ground. I usually refer to it as a jump grace period.
The logic goes a little something like this: First I have a jumpGraceTimer and a jumpGraceTime. jumpGraceTime is a fixed value of how may frames I will allow the player to still have access to their jump after they leave the ground. Usually this is around 3 to 5 frames (at 60 frames per second) depending on the speed of the player and the game. The timer counts down from that value to 0 whenever the player is no longer touching the ground (no collision at y + 1) when they didn't jump. If they did jump, I assume that they are purposely leaving the ground and I don't need to help them, so I set the timer to 0. When the player is touching the ground, that timer is always set to jumpGraceTime, so that it's ready to count down when the ground collision is no longer happening.
Now when I check to see if my player can actually jump or not, I'm actually checking to see if they are on the ground (onGround) or if the jumpGraceTimer is greater than 0. If they indeed can jump, then I do the jump logic and set the jumpGraceTimer to 0 manually. I don't want the player to be able to jump multiple times if they happen to be really good at mashing.
You can implement this in any way you want really, but this is just my go to technique! (Edit: Actually I guess I could just check to see if the graceTimer is > 0... but there might be some reason why I'm still checking onGround || graceTimer > 0... I can't remember now, haha!)
So here we go again. Our player runs off the ledge and hits jump just 2 frames after they've left the ground...
But thanks to our jumpGraceTime that allows the player to be off the ledge for 3 to 5 frames before their jump is taken away, they can jump!
And all is right in the world. If you do this right then the player wont suspect a thing. A very popular platformer game that you've probably heard of before (Canabalt) makes use of this technique! If you really try to push the limit, you'll notice that your character can actually be totally off the ledge and still jump as if his feet were on solid ground, but just for a fraction of a second.
Just be careful with how much time you allow the player to have before they can no longer jump. I implemented this in Offspring Fling with a very small timing window and it works just fine. However, we implemented this technique in Snapshot as well, but the timing window might actually be too generous in this case. There are times where you can clearly see Pic falling before you push the jump button, and this can sometimes cause a weird disconnect, or reveal the "man behind the curtain" which can make the player feel a little disrespected.
Little tricks like this that help the player feel more in control can really help your platformer shine! But you don't want to go overboard and baby the player either. Let them roam free and hurt themselves sometimes and learn from their mistakes, but also make sure they don't get frustrated by tiny details like pushing a button too early or too late by fractions of a second (unless we're talking about Street Fighter.)
Take a look at this typical platforming scenario. Our player is barreling toward a ledge at top speed, just holding right without a care in the world. They're going to want to jump when they get to the end of that ledge, and they're probably going to want to hit jump as late as possible so that they get the maximum distance out of their jump.
Ideally they would hit the jump button right now. Their character is still on the ground, and in the most simple implementation of a platformer jump system then this would be fine. I assume that the code would be just something along the lines of if (onGround) { jump(); } and onGround would evaluate to true if our player collides with the ground at y + 1.
But what happens if the player just slightly overshoots the ledge?
If our most basic platforming system is only looking at the player's y + 1 to detect the ground, then the player will not be able to jump in this case. At this point you might ask well doesn't that make sense? The player isn't on the ground, so they can't jump... that's how it would work in the real world!
This isn't the real world though, this is video games! If you're playing a fast paced platformer running at 60 frames per second, it's incredibly easy to hit the jump button right after you run off a ledge, but to your feeble human eyes it looked like you hit the jump button while you were still on the ground. This can be incredibly frustrating, especially if you're trying to make jumps across some pretty wide gaps and you're trying to maximize your jump distance.
What I like to do for my games for this situation is to introduce a timer that keeps track of how long it has been since the player last touched the ground. I usually refer to it as a jump grace period.
The logic goes a little something like this: First I have a jumpGraceTimer and a jumpGraceTime. jumpGraceTime is a fixed value of how may frames I will allow the player to still have access to their jump after they leave the ground. Usually this is around 3 to 5 frames (at 60 frames per second) depending on the speed of the player and the game. The timer counts down from that value to 0 whenever the player is no longer touching the ground (no collision at y + 1) when they didn't jump. If they did jump, I assume that they are purposely leaving the ground and I don't need to help them, so I set the timer to 0. When the player is touching the ground, that timer is always set to jumpGraceTime, so that it's ready to count down when the ground collision is no longer happening.
Now when I check to see if my player can actually jump or not, I'm actually checking to see if they are on the ground (onGround) or if the jumpGraceTimer is greater than 0. If they indeed can jump, then I do the jump logic and set the jumpGraceTimer to 0 manually. I don't want the player to be able to jump multiple times if they happen to be really good at mashing.
if (jumpInput) {
if (onGround || graceTimer > 0) {
jump();
}
}
//somewhere else in the code:
public function jump():void {
//pretend theres more jumping logic here
graceTimer = 0;
}
You can implement this in any way you want really, but this is just my go to technique! (Edit: Actually I guess I could just check to see if the graceTimer is > 0... but there might be some reason why I'm still checking onGround || graceTimer > 0... I can't remember now, haha!)
So here we go again. Our player runs off the ledge and hits jump just 2 frames after they've left the ground...
But thanks to our jumpGraceTime that allows the player to be off the ledge for 3 to 5 frames before their jump is taken away, they can jump!
And all is right in the world. If you do this right then the player wont suspect a thing. A very popular platformer game that you've probably heard of before (Canabalt) makes use of this technique! If you really try to push the limit, you'll notice that your character can actually be totally off the ledge and still jump as if his feet were on solid ground, but just for a fraction of a second.
Just be careful with how much time you allow the player to have before they can no longer jump. I implemented this in Offspring Fling with a very small timing window and it works just fine. However, we implemented this technique in Snapshot as well, but the timing window might actually be too generous in this case. There are times where you can clearly see Pic falling before you push the jump button, and this can sometimes cause a weird disconnect, or reveal the "man behind the curtain" which can make the player feel a little disrespected.
Little tricks like this that help the player feel more in control can really help your platformer shine! But you don't want to go overboard and baby the player either. Let them roam free and hurt themselves sometimes and learn from their mistakes, but also make sure they don't get frustrated by tiny details like pushing a button too early or too late by fractions of a second (unless we're talking about Street Fighter.)
Comments
The trick you describe works well in combination with this if the player should be able to jump from a low tunnel exiting out from a wall, without hitting the ceiling too easily, or running off the edge before jumping.
Also forgive the " or whatever is happening in the post sometimes, got a php function that's acting up somewhere at the moment -_-
Post your comment!