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