How to make correct state machine?

Godot Version

4.1.1

Question

I tried to make state machine for player but it seems to not working. Running state and its animation is not happening after Idle state.

extends CharacterBody2D

const max_spd: int = 110
const accl: int = 10
const friction: int = 16

@onready var anime = $AnimatedSprite2D

enum States {IDLE, RUN, DASH, ATTACK}
var player_state = States.IDLE

func _physics_process(delta: float) -> void:
	if player_state != States.DASH and player_state != States.ATTACK:
		get_input(delta)
		
		print(velocity)
		
		if velocity.x and velocity.y == 0:
			player_state == States.IDLE
		elif velocity.x and velocity.y != 0:
			player_state == States.RUN
		
	move_and_slide()
	update_animation()

func get_input(delta):
	var input = Vector2(
		Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left"),
		Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
	).normalized()
	
	var lerp_weight = delta * (accl if input else friction)
	velocity = lerp(velocity, input * max_spd, lerp_weight)

func update_animation():
	if velocity.x > 0:
		anime.flip_h = true
	if velocity.x < 0:
		anime.flip_h = false
	match(player_state):
		States.IDLE:
			anime.play("idle")
		States.RUN:
			anime.play("running")

if conditions do not bundle variables together with and, consider if velocity.x:, this sadly evaluates to

if velocity.x != 0.0:

so when you use velocity.x and ... it evaluates to velocity.x != 0.0 and ... and your full line looks like this when expanded

if velocity.x != 0.0 and velocity.y == 0.0:

But floating point values such as velocity very rarely exactly equal any value, you may prefer to use is_zero_approx.

if velocity.is_zero_approx():
	player_state == States.IDLE
else:
	player_state == States.RUN


And finally you likely recieve an error along the lines of “Statement has no effect” for these player_state == ... lines. Because two equal signs == is for comparing values, your program takes player_state, checks if it is currently equal to States.IDLE and throws the result away. It doesn’t assign anything. You want to use a single equals sign. Make sure to check your errors and warnings when writing scripts.

if velocity.is_zero_approx():
	player_state = States.IDLE
else:
	player_state = States.RUN
1 Like