Coyote Time

Problem

Your platformer jumping feels “off”. Players don’t have good control and sometimes they “miss” jumping off the edge of platforms.

Solution

The answer to this problem is to use a technique called “coyote time”. This gives the player a greater feeling of control and a little “wiggle room” around the process of jumping from the edges of platforms.

“Coyote time” works like this:

If the player walks off the edge of a platform, for a few frames afterward, we still allow them to jump as if they were still on the ground.

Origins

The name “coyote time” comes from the famous cartoon coyote, who wouldn’t fall until he looked down:

alt alt

We’re going to add this to an already existing platform character. See the Platform character recipe for how to set one up.

To handle the timing, we’ll add a Timer node called CoyoteTimer and set it to One Shot.

There are a few new variables we’ll need to keep track of coyote time:

var coyote_frames = 6  # How many in-air frames to allow jumping
var coyote = false  # Track whether we're in coyote time or not
var last_floor = false  # Last frame's on-floor state

Since we’re using frames to set the duration, we can translate that to time when setting the Timer’s length in _ready():

$CoyoteTimer.wait_time = coyote_frames / 60.0

Each frame we’ll store the current value of is_on_floor() to be used in the following frame, so put this in _physics_process() after the move_and_slide():

    last_floor = is_on_floor()

When we detect the jump input, we need to check if the character is on the floor or in coyote time:

    if Input.is_action_just_pressed("jump") and (is_on_floor() or coyote):
        velocity.y = jump_speed
        jumping = true

Coyote time begins if the player walks off the edge of a platform. That means that they are no longer on the floor, but were on the floor in the previous frame. We can check that like this, and start the timer if we did just transition from on- to off-floor:

    if !is_on_floor() and last_floor and !jumping:
        coyote = true
        $CoyoteTimer.start()

The CoyoteTimer tells us when the coyote state ends:

func _on_coyote_timer_timeout():
    coyote = false
Implementing in 3D

You can apply the same process to 3d characters.

Download This Project

The character in the Moving Platforms project has coyote time implemented.

Download the project code here: https://github.com/godotrecipes/2d_moving_platforms