Many players describe the controls of a good platformer as «precise» or «responsive». They rarely know that, behind the scenes, the game is helping them: it accepts jumps that are slightly late, remembers presses that are slightly early, and nudges the character a few pixels so it does not bump into a corner. These tricks, often grouped under the label of game feel, do not make the game easier in the strict sense: they make it fair, because they make the result match the player's intention.
The problem: humans are not frame-perfect
At 60 frames per second, each frame lasts about 16.7 milliseconds. Nobody presses a button with that precision consistently. If the game demands that jump be pressed exactly while the character is still on the edge of the platform, some jumps will fail, and the player will feel clearly that they pressed in time. They are right: from their point of view, they did.
Coyote time
The name comes from cartoons in which the coyote runs past the edge of a cliff, hangs in mid-air for a moment and only then falls. Coyote time gives the player that same moment: for a short interval after leaving a platform, jumping is still allowed.
if on_ground:
time_since_ground = 0
else:
time_since_ground += dt
can_jump = time_since_ground < COYOTE // for example 0.1 s
Important details:
- coyote time should be granted only if the character left the ground by falling, not after a jump, otherwise it becomes an accidental double jump;
- once used, it must be reset immediately;
- typical values are on the order of a few frames, about a tenth of a second: enough to correct imprecision, too little to be noticed.
Input buffering
The opposite problem: the player presses jump a moment before touching the ground. Without help, the press happens in mid-air, is not valid, and when the character lands nothing happens. An input buffer stores the request for a short time:
if jump_just_pressed:
jump_buffer = BUFFER // for example 0.1 s
else:
jump_buffer -= dt
if jump_buffer > 0 and can_jump:
jump()
jump_buffer = 0
The same principle applies to many other actions: an attack pressed during the previous attack's animation, a dodge requested while still landing, a combo in a fighting game. The game «remembers» the request and carries it out at the first valid moment.
Corner correction
During a jump, if the character's head clips the corner of a block above by one or two pixels, the collision stops it abruptly. The player perceives an obstacle that was not there. Corner correction checks whether moving the character a few pixels left or right makes the collision disappear and, if so, shifts it and lets the jump continue.
The same applies sideways: a character arriving a couple of pixels below the edge of a platform can be lifted up automatically instead of stopping against it.
Generous and stingy hitboxes
Collision shapes do not have to match the artwork:
| Element | Typical choice | Reason |
|---|---|---|
| Player hitbox against hazards | Smaller than the sprite | Grazing hits do not count, the game feels fair |
| Pickup hitboxes | Larger than the sprite | Collecting is rewarding, missing by a pixel is frustrating |
| Enemy hitboxes against player attacks | Slightly larger | Visually close hits land |
Hit stop and impact feedback
Game feel is not only about fairness, but also about a sense of weight. Some widespread techniques:
- hit stop: when a hit lands, the game freezes for a very few frames. The brain registers the impact, and the blow feels more powerful.
- flash: the enemy that was hit turns white for an instant.
- knockback: the target is pushed back a few pixels.
- squash and stretch: the character stretches slightly when jumping and squashes on landing, making movement livelier.
Combined with a suitable sound and a slight screen shake, these elements turn a flat interaction into a satisfying one.
Tuning without overdoing it
Every aid has a cost if it becomes visible. Coyote time that is too long lets you clearly jump from thin air; a buffer that is too long triggers jumps the player no longer wanted. Some practical advice:
- start from small values, on the order of 5-6 frames, and adjust through play;
- express values in seconds, not frames, so as not to depend on frame rate;
- have people who do not know the game play it, and watch where they complain about a command «not registering»;
- make every parameter editable while the game is running.
In my prototyping work I have found a small panel that toggles each aid on and off very useful: playing the same level with and without coyote time makes the difference immediately obvious.
In short
- Humans are not frame-perfect: the game must take this into account.
- Coyote time allows a jump for a moment after leaving the edge.
- An input buffer remembers early presses and executes them at the first valid moment.
- Corner correction and tuned hitboxes remove collisions that feel unfair.
- Hit stop, flashes and squash and stretch give impacts weight, as long as you do not overdo it.