This blog comes from Case Portman from Studio Thunderhorse, who are currently hard at work on Flynn: Son of Crimson. It's a look into the design and execution of perfect feeling platformer jump mechanics.
Have you ever played a platforming game and thought to yourself, “This feels sorta clunky” but couldn’t put your finger on why? Or better yet, the opposite in which the controls and movement feel super snappy and fluid yet you’re still wondering how the developers did it? What is this hidden magic that without it, could make a potentially amazing game fall flat?
Let me introduce you to a little thing called input buffering and it’s just as important brother, edge tolerance (or “Coyote Time” if you’re down with the kids!). Two very important features that I’ve implemented into our main project Flynn: Son of Crimson.
This is the term used for giving an input an instruction (In this case, the press of a button) to keep in memory until it's able to perform said instruction. A good example of this is including a small amount of time in which the player can press the jump button (while they’re still in midair) causing the character to jump once they've hit the ground.
This technique gives the player a small margin of error if the jump button is pressed too early thus making every intended jump perform successfully. Imagine a difficult level containing a multitude of quick-fire jumps to prevent damage being taken, it would require the player to make sure every jump input was pressed whilst on the ground meaning any early inputs (even a single pixel from the ground) would not be registered. It’s a small, hidden feature that generally goes unnoticed until it’s none existent.
So, how do we add this to our game? It’s dead simple and only requires a few extra lines of code! If you've already implemented your player jump code, then you've most likely already implemented the obligatory "If grounded then jump" to a simple key/button press, which is a perfect start as all we need to do is shuffle a few lines of code around.
There are various ways to apply a buffer to this, but we'll stay within the same block of text to keep things concise and create a simple counter. We're going to first want to declare two variables in the player object’s CREATE event before any of this happens, those variables will be
buffer_max. We'll be referring to these as we go and can be tweaked once we have the basic buffering in and working.
Next up, in the STEP event, we're going to shuffle around the jump code so that it involves the above variables. Instead of going straight to the “jump” part of the code on the button press, we’ll set
buffer_counter to equal
buffer_max (in this case to the value of 4 as set in the Create Event). Now that the
buffer_counter isn’t equal to 0, the following code will run:
At any point while
buffer_counter is greater than 0, it counts down every frame until it settles back to 0 (
buffer_counter -= 1). If
buffer_counter is greater than 0 and the player is on the ground (i.e. from landing) then the jump will be successfully performed whilst also resetting
buffer_counter back to 0, this ensures no extra jumps will be performed until another jump input has been triggered.
Wa-lah! Now your jump action will perform even if you press the jump button before landing, pretty cool right? We’ve made jumping much more responsive with just a few lines of code. Input buffering doesn't stop there though, you can add it to pretty much anything you like such as attacking, dodging, even navigating menus.
Coyote Time is another hidden feature that gives the player a fair “safety net” for an otherwise missed jump input just after leaving a ledge or platform. This is effectively the opposite of a buffered jump input since the action will execute upon pressing the button later than intended rather than earlier.
Implementing Coyote Time is a little more involved than jump buffering but it’s still not too difficult if you’re keeping track of your jump code. We’ll start with declaring a few more variables in the CREATE event. Since we’re going to be tying this code together with the jump buffer we’re going to not only create a new counter but also two booleans called
on_ground, these are pretty self-explanatory but also important.
coyote_maxare values you can tinker with later to suit your needs.
Next up we’re jumping back into the STEP event. We’ll first tie the boolean variable
on_ground to whether or not the player has solid ground below them. You may have done this already, but it’s good to keep things clean in the future.
Similar to the jump buffer, we have a counter that counts down to 0 while the player IS NOT on the ground except the trigger to count down isn’t tied to a button press, instead, it’s the moment the player leaves the ground by stepping off/away from it, NOT by jumping. The variable
jumped is important here since this prevents any accidental and/or double jumps whilst in the air. Also, note that the following block of code should be placed BEFORE the jump buffer code.
I’ve tried to comment the code as clear as possible so hopefully, it’s understandable. As you can see, the code is almost the direct opposite to the jump buffer with a few more checks. Let’s now go back to the jump buffer code and tie it all together.
The part outlined in blue used to be
place_meeting and has been replaced with the boolean
on_ground since that variable now holds the same information. The part outlined in red is where we insert the boolean for
jumped which ensures that the player cannot perform another jump straight after the first (i.e. in midair).
That’s all there is to it! Below shows both mechanics in full to get a good overview of what your step event might look like once everything has been applied.
To finish, here are two round-up gif animations showing how these two features work visually.
It’s easy to forget about simple fundamental mechanics such as jumping as once you have your jump code in, it sits there doesn’t get touched. Don’t settle for a simple [if grounded: jump] mechanic if your game features jumping. The basic core features of your game should be a top priority to feeling as good as they possibly can. Sure your mid-air uppercut multi-hit special smash blast™ feels AMAZING but do your simple jumps and movement, or could they feel better? I bet they could!
If you need any help/advice about anything I’ve covered or just want to say hi, drop me a message on Twitter: @Case_Portman. Alternatively, if you wish to follow along with updates for Flynn: Son of Crimson, follow @ThunderhorseCO.