Fox Studios logo Fox StudiosGame projects, devlogs and Scratch builds
Games

Coyote Time and Jump Buffering in a Scratch Platformer

Every time I test a beginner's first Scratch platformer on someone who has never seen it, the same complaint comes up within a minute: "I pressed jump and it didn't jump." The maker usually insists the code is fine, and technically it is.

A pixel character stepping off a ledge with a small timing window marked beneath it

Every time I test a beginner's first Scratch platformer on someone who has never seen it, the same complaint comes up within a minute: "I pressed jump and it didn't jump." The maker usually insists the code is fine, and technically it is. The jump script runs when the sprite is touching the ground and the key is pressed. The problem is that players do not press keys at the exact moment the code expects, and the game punishes them for being a few hundredths of a second off.

Commercial platformers solved this years ago with two small tricks, and both fit into a Scratch project in about fifteen blocks. Once you add them, the same level suddenly feels fair, and testers stop blaming the controls.

Why a "correct" jump feels broken

Think about what happens at the edge of a platform. The player runs right, sees the gap coming, and presses jump a fraction of a second after the sprite has walked past the edge. On the screen, it looks like they jumped from the edge. In your code, the sprite was no longer touching the ground on the frame the key went down, so the jump never happened. The sprite falls into the gap, and the player is certain they pressed the button in time. From where they sat, they did.

The opposite happens when landing. A player falling toward a platform presses jump slightly early, just before touching down, expecting to bounce straight back up. The key press lands on a frame where the sprite is still in the air, so nothing happens. By the time the sprite lands, the key has been released.

Scratch makes both problems more noticeable than they would be elsewhere, because projects run at 30 frames per second. Each frame lasts about 33 milliseconds, so the window where "touching ground" and "key pressed" overlap can be a single frame. That is a very small target for a human hand.

What Celeste does about it

Celeste, the platformer by Maddy Thorson and Noel Berry, is famous for being hard but fair. Its developers have talked publicly about a set of hidden forgiveness rules that make it feel that way. Two of them matter most for us.

Coyote time lets you jump for a short moment after walking off a ledge, named after the cartoon coyote who runs off a cliff and only falls once he looks down. In Celeste, this window is roughly a tenth of a second.

Jump buffering remembers a jump press for a short moment before you land, and fires the jump the instant you touch the ground.

Neither trick makes the game easier in a way players notice. They just make the game do what players already believed they asked for. Our article on why the simplest mechanics are hardest to perfect has more on this kind of invisible tuning.

Adding both to a Scratch platformer

I am assuming you already have a basic platformer with a variable for vertical speed, often called y velocity, and a check for whether the player is touching the ground. If not, our guide to getting into game development with Scratch walks through that first.

You need two new variables, both "for this sprite only": coyote and jump buffer. Then make these changes inside your main forever loop.

  1. Count frames since the ground. If the sprite is touching the ground, set coyote to 0. Otherwise, change coyote by 1. Now the variable tells you how many frames have passed since the player was last standing on something.
  2. Count frames since the jump key. If the jump key is pressed, set jump buffer to 0. Otherwise, change jump buffer by 1. This tells you how many frames ago the player last pressed jump.
  3. Replace your jump condition. Delete the old "if touching ground and key pressed" block. In its place, use: if coyote is less than 4 and jump buffer is less than 4, then set y velocity to your jump strength.
  4. Use up both windows when you jump. Inside that same if block, set coyote to 99 and jump buffer to 99. Without this step, the player can jump twice in mid-air, because the counters are still small on the next frame.
  5. Stop holding to repeat. If your game should not let players bounce endlessly by holding the key, only reset jump buffer to 0 on the frame the key goes from up to down. A third variable, key was down, stores last frame's state so you can compare.

The number 4 gives you three frames of grace, around 100 milliseconds at Scratch's 30 frames per second. That is close to what Celeste uses. Try 3 for a stricter feel or 6 for a very forgiving one, and compare.

The mistake I made the first time

When I first added coyote time to one of my own projects, I set the window to 10 frames, about a third of a second, reasoning that more forgiveness could not hurt. It did. Players could now walk visibly off a ledge, hang in the air for a beat, and still jump. It looked like a bug, and two testers asked whether the game was glitched. The point of the trick is that the player never notices it. Once it becomes visible, it stops feeling fair and starts feeling broken in a new direction.

The other thing I got wrong was where in the loop I put the checks. If you update coyote after moving the sprite, but check the jump condition before, you can end up a frame out of step and the effect feels inconsistent. Update both counters at the top of the loop, check the jump straight after, and move the sprite last.

Test it the honest way

You cannot judge this yourself. You already know where the edges are, and your hands have adapted to your old, unforgiving code. The only real test is someone who has never played your game.

Make two copies of the project, one with the changes and one without, and do not tell your tester which is which. Ask them to play the same short level in each and say which one has "better controls". In the five tests I ran on our last workshop project, all five picked the version with coyote time and buffering, and none could say exactly why. That is about as clean a result as you get with playtesting, and it matches what our notes on playtesting for first-time makers describe.

Your task for this week

Open your most recent platformer, add the two counters, and set both thresholds to 4. Then hand it to one person who has not played it and watch the first ledge they reach. If they make the jump without comment, you are done. If they still miss, look at where the counters sit in your loop before changing the numbers. More small game-feel fixes are collected in our games section.

MK
Mira Kovac

Mira teaches coding to beginners and writes the step-by-step guides, always testing each one on someone who has never coded before.

More posts by Mira

More in Games

01doorganico 084goad 3hot8 4465456 after5internprogram ahandfulofblessings ahmadpc ahomcybersecurity allodialresources annodex antiquesandperiodcollectibles aotc asianworldkashmir beedlectrics bloggertemplatefree bluefeatheragency bodyweightsolution campaign08blog carfixadvisor catstreetcollective cbstvsports cnfanspurchasing committeeof500yearsofdignityandresistance covertopsdjs cs-kaiyuangame cuestacomunicaciontotal cxoutlet dancebetgame deskgearhub destinyvillastay detectmagazine di33 diamondsteelbuildings donmo dyanadropship emarsysfinance emimattl escapechan eskitarih evautoplay everythingweddings-orlando farmzone feedviewerapp gamevui123 gleasongrade greetingsday hacklabasu haskell iw-kaiyun jagoanproperti jilidskripsi joltbusinessfinance juegodepokergratis juegospucca kaeru-festival latestmehndidesigns lestanzediottaviano litemagazines localcommunityhero lustrsazan mariashebets menswheels newwebstechs1 nikkit ootheday oxigenvpn plurfitness prefetial probudgetcarpetcleaning psychicmrsmartin pyaten qvantor rejoignezlogis rexzbot riselayouts ruchin rwxqsgd5 sakaltime shibiaowang shop-bot skrtips strcoding tetapatrium topselller uneplanteartificielle vipertechcr webtech1223411 wo-kygaming yamaha-mekar yeknava yoybuysheets zenunwa yamaha-mekar jilidskripsi ankertoto ankertoto ankertoto ankertoto