Problems with enemy state machine

Godot Version

4.0

Question

I have a 2d top-down platformer . In it i have a enemy with a state machine . it has idle , chase and death states . The problem is , when i instantiate multiple copies of the enemy , only the first copy works . the rest are all broken . for example , the first copy works , and it chases me . while the second or any other instances dont work , they just stay in the same place . althoug when the first copy chases me , the other instances also go under the chasing animation but they stay in the same place . Im new to using state machines . can somebody help me with what’s goin on ?? thanks

Can you share your code or otherwise we will just be guessing at the problem.

# Don't forget to use the code tags!
# Otherwise people may not bother reading it.
3 Likes

sure , here is the state machine code and the walk ( chasing ) code attached to the FSM .

state machine :

extends Node

@export var initial_state : states
var current_state : states
var player_states : Dictionary = {}

func _ready():
for child in get_children():
if child is states:
player_states[child.name.to_lower()] = child
child.statetransitioned.connect(on_child_transition)

if initial_state:
	initial_state.enter()
	current_state = initial_state

func _process(delta):
# Ensure that current_state is not null before calling update
if current_state != null:
current_state.update(delta)

func on_child_transition(state, new_state_name : String):
# Only transition if the current state exists and is not freed (null check)
if state != current_state or current_state == null:
return

var new_state = player_states.get(new_state_name.to_lower())

# Ensure the new state is valid
if new_state == null:
	return

if current_state != null:
	current_state.exit()

new_state.enter()
current_state = new_state

func free_state(state: states):
# Clear references and safely free the state
if state == current_state:
current_state = null # Clear current_state reference
state.queue_free()

walk/chase state :

extends states
class_name dragaur_walk

@export var enemy_anim : AnimatedSprite2D
@onready var enemy_body = get_tree().get_first_node_in_group(“enemy”)
@onready var player : CharacterBody2D = get_tree().get_first_node_in_group(“player”)
@onready var colli_enemy = $“…/…/CollisionShape2D”

func enter():
print(“enemy enetered walking”)
enemy_anim.play(“WALK”)

func update(_delta : float):
var hunt_distance = player.global_position.distance_to(enemy_body.global_position)

if hunt_distance < 70:
	var move_direction = player.global_position - enemy_body.global_position
	enemy_body.velocity = move_direction.normalized() * 20
	
	# Flip the sprite based on direction
	if enemy_body.velocity.x > 0:
		enemy_anim.scale.x = -1
		colli_enemy.position = Vector2(12.594, -8.571)
	else:
		enemy_anim.scale.x = 1
		colli_enemy.position = Vector2(-2.857, -8.571)

	enemy_body.move_and_slide()
	enemy_anim.play("WALK")
	
	
else:
	statetransitioned.emit(self, "dragaur_idle")
	print("enemy into idle state")

func _on_area_2d_area_entered(area):
print(“enemy hit”)
statetransitioned.emit(self, “dragaur_hurt”)

It is hard to read your code because you have not used the code tags properly, but I think the problem here is that the signal to change state is being picked up by all your entities. So when your working entity goes into the chase state, all of the entities do.

The reason they do not chase you is because they are not close enough (I am guessing) as your movement depends on distance.

My advice would be to revisit your state machine. I think fundamentally it has a few issues in the way you have approached it. For instance I have no idea why you would queue free a state.

Hope that helps,

Paul