Godot Version
4.4
Question
Hi! This is my first time creating a state machine for a game and I’m having some difficulty making the enemy AI switch states. The state machine relies on a series of timers to switch between the following states: {IDLE, SCATTER, CHASE, EVADE, EATEN} and once one timer for a state times out, it should switch to another state. My issue is that when the timer expires, the AI will not switch states and will instead be trapped in a loop of the same state. I have gone over my code repeatedly and I cannot seem to find a solution, although I’m sure that its very obvious, and I was wondering if I could get some help here. Below I’ve included the edited code for my enemy node and for the GameManager node, which contains the timers that should cause the enemy to switch states
GameManager
#code cut for readability
#handle timers
var scatter_timer_active : bool = false
var chase_timer_active : bool = false
var evade_timer_active : bool = false
func _process(delta: float) -> void:
#code cut for readability
func _on_chase_timer_timeout() -> void:
chase_timer_active = false
get_tree().call_group("Ghosts", "scatter_mode")
$Timers/ScatterTimer.start()
func _on_scatter_timer_timeout() -> void:
scatter_timer_active = false
get_tree().call_group("Ghosts", "chase_mode")
print("Timeout!")
$Timers/ChaseTimer.start()
func _on_evade_timer_timeout() -> void:
evade_timer_active = false
get_tree().call_group("Ghosts", "scatter_mode")
$Timers/ScatterTimer.start()'''
Heres the code for the enemy class:
extends CharacterBody2D
class_name Ghost
#setup state machine
enum States {IDLE, CHASE, SCATTER, EVADE, EATEN}
@export var state : States = States.IDLE
#finds player
var target
#handle ghost movement (cut for readability)
#track how many times scatter mode has been entered (enemy will no longer enter scatter mode after the third loop)
@export var scatter_count : int = 0
func _physics_process(delta: float) -> void:
get_target()
$State.text = str(state)
navigator.target_position = target.position
direction = (navigator.get_next_path_position() - global_position)
direction = direction.normalized()
velocity = Vector2(movement_speed, movement_speed) * direction
move_and_slide()
func get_target():
if state == States.CHASE and GameManager.chase_timer_active == false:
target = get_parent().get_parent().find_child("Player")
elif state == States.SCATTER and scatter_count <= 3 and GameManager.scatter_timer_active == false:
target = get_parent().get_parent().find_child("ScatterPoints").find_child("InkyScatter")
scatter_count += 1
func _on_ghost_hitbox_body_entered(body: Node2D) -> void:
if body is Player:
print("die!")
func chase_mode():
state = States.CHASE
GameManager.chase_timer_active = true
func scatter_mode():
state = States.SCATTER
GameManager.scatter_timer_active = true