Infinite jump when implementing Coyote Time in Finite State Machine

Godot Version

Godot 4.4.1-stable

Question

Hi everyone. I’ve been working on my first platformer and run into an issue where attempting to implement Coyote Time in a Finite State Machine, based on this one, results in an infinite jump while in the air.

Here’s the code, which I currently have in the Jump_state script

extends State
#region Variables
@export 
var idle_state: State
@export 
var run_state: State
@export 
var fall_state: State
@export 
var attack_state: State
@export
var jump_velocity: int = -400
@onready var coyote_timer: Timer = %CoyoteTimer
var coyote_jump: bool = false
#endregion

#region Functions
func enter() -> void:
	super()
	parent.velocity.y = jump_velocity
	
	

func process_physics(delta: float) -> State:
	if !parent.is_on_floor():
		parent.velocity.y += gravity * delta
		if coyote_timer.is_stopped():
			coyote_timer.start()
		else:
			coyote_jump = true
			coyote_timer.stop()
	
	if parent.velocity.y > 0:
		return fall_state
			
	if Input.is_action_just_pressed("Jump") && coyote_jump:
			parent.velocity.y = jump_velocity
			coyote_jump = false
			print("Coyote Jump check")
		
	var movement:= Input.get_axis("Left", "Right") * speed
	
	if movement != 0:
		parent.animations.flip_h = movement < 0
	parent.velocity.x = movement
	var was_on_floor := parent.is_on_floor()
	parent.move_and_slide()
	
	if was_on_floor && !parent.is_on_floor():
		coyote_jump = true
	
	if parent.is_on_floor():
		if movement != 0:
			return run_state
		return fall_state
	
	return null

func _on_coyote_timer_timeout() -> void:
	print("Timer works")
	coyote_jump = false
#endregion

Picture a player that is infinitely falling. On frame 1, the player is in the air. Therefore, the first check (if !parent.is_on_floor()) succeeds. If the coyote timer has stopped, it is started.

On frame 2, the player is still falling. The coyote_jump variable is set to true and the timer is stopped. The player can now jump in the air once. Let’s say that the player does.

Frame 3, the player is still in the air. The timer is stopped, so it is once again started.

Frame 4. Player is in the air. Timer is running, so coyote_jump is set to true and the timer is stopped. The player can now jump in the air again.

You should probably want to keep track of the number of times the player is allowed to jump while in the air, and prevent a jump from being processed if the player tries to jump more often than allowed. The number of total jumps in the air can be reset to zero whenever the player makes contact with the ground.

1 Like