Make Platformer Jump Feel Satisfying using Coyote Timer

with vs without coyote timer in platformer

In all of my older platformer games, the jumping always felt slightly off. Big production titles like Mario, Lep’s World, or pretty much any mainstream platformer felt smooth and responsive. But in mine, the player would often fall if you were running and tried to jump right at the edge of a platform.

For the longest time, I assumed the issue was in my collision shapes or something to do with physics. Turns out, it was something else entirely.

Most platformers actually let you jump for a brief moment even after you’ve technically left the ground. That tiny grace period makes the game feel more responsive—so even if your timing is a bit off at the edge, the game still lets the player jump.

What is Coyote Timer?

Typically, in a platformer game, you might think of following code to make player jump:

var is_on_ground = false

func _physics_process(delta):
    is_on_ground = is_on_floor()

    if Input.is_action_just_pressed("jump") and is_on_ground:
        velocity.y = -JUMP_FORCE

But the problem here is, the player has to be extremely precise when jumping at the edge of a platform. But our average human reaction time is around 250 milliseconds (0.25 seconds), so it’s common to be just a bit late. That slight delay can make the character fall instead of jumping, just because you weren’t perfectly on time.

To make jumps feel smoother and more forgiving, we can add a small window, usually around 0.1 to 0.15 seconds, after the player leaves the ground during which jumping is still allowed. It’s short enough to keep the game challenging (since it’s still faster than our reaction time), but long enough to make the controls feel responsive. Here’s how you can implement it:

const COYOTE_TIME = 0.1  # 100 milliseconds

var coyote_timer = 0.0
var is_on_ground = false

func _physics_process(delta):
    is_on_ground = is_on_floor()
    
    # Update the coyote timer
    if is_on_ground:
        coyote_timer = COYOTE_TIME  # reset when grounded
    else:
        coyote_timer -= delta  # count down when in air

    if Input.is_action_just_pressed("jump") and coyote_timer > 0:
        velocity.y = -JUMP_FORCE
        coyote_timer = 0  # cancel coyote time once jump is used

Thank you for reading <3

Leave a Reply

Your email address will not be published. Required fields are marked *