I dont understand how to use FSM for all Enemies

I have an FSM as a scene with two states inside. It works for a single enemy, but I don’t understand how to implement it properly for all different enemies. Is it okay to link the FSM to BaseEnemy, or should we create another scene with all spawning enemies and include the FSM there? Which approach is correct and better?

FSM

extends Node

class_name FiniteStateMachine


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

func _ready() -> void:
	for child in get_children():
		if child is EnemyState:
			states[child.name.to_lower()] = child
			child.state_transition.connect(change_state)
		if initial_state:
			initial_state.Enter()


func _process(delta: float) -> void:
	if current_state:
		current_state.update(delta)

func change_state(old_state : EnemyState, new_state_name :String):
	
	if old_state != current_state:
		return

	var new_state = states.get(new_state_name.to_lower())
	if !new_state:
		print("New state is empty")
		return
		
	if current_state:
		current_state.Exit()
		
	new_state.Enter()
	
	current_state = new_state

Sounds like you can instantiate it to your enemy scene? Could you share your scene tree screen shots?

Yes, I wrote it in the BaseEnemy class. Is that a good decision?

The FSM retrieves the enemy from the Base class, and we pass the sprite’s animation to the state’s enter method. Below is all my code.

BaseEnemy

extends Node

class_name BaseEnemy

var damage:int
var speed:float
@export var sprite: AnimatedSprite2D
@export var fsm_scene_path: String = "res://enemies/FSM/FSM.tscn"
var fsm: FiniteStateMachine


func initialize(damage:int,speed:float) -> void:
	self.speed = speed
	self.damage = damage

func _ready() -> void:
	var fsm_scene = load(fsm_scene_path)
	if fsm_scene:
		fsm = fsm_scene.instantiate() as FiniteStateMachine
		add_child(fsm)  
		fsm.initialize(self)  
		print("FSM Added to the enemy ", name)
	else:
		print("Error FSM could not been added ", fsm_scene_path)

func get_character_body() -> CharacterBody2D:
	return self.get_node("CharacterBody2D") as CharacterBody2D
	
func _process(delta: float) -> void:
	pass

UpdatedFSM

extends Node

class_name FiniteStateMachine


var states:Dictionary = {}
@export var initial_state : EnemyState
var current_state : EnemyState
var owner_enemy:Enemy


func initialize(enemy: Node) -> void:
	self.owner_enemy = enemy
	for child in get_children():
		if child is EnemyState:
			states[child.name.to_lower()] = child
			child.state_transition.connect(change_state)
		if initial_state:
			initial_state.Enter(self.owner_enemy)
			current_state = initial_state


func _process(delta: float) -> void:
	if current_state:
		current_state.update(delta)

func change_state(old_state : EnemyState, new_state_name :String):
	
	if old_state != current_state:
		return

	var new_state = states.get(new_state_name.to_lower())
	if !new_state:
		print("New state is empty")
		return
		
	if current_state:
		current_state.Exit()
		
	new_state.Enter()
	
	current_state = new_state

ChaseState

extends EnemyState

class_name ChaseState

var player: CharacterBody2D = null
var enemy : Enemy
var enemy_character: CharacterBody2D
var sprite:AnimatedSprite2D

var move_direction: Vector2

func Enter(owner_enemy):
	self.enemy = owner_enemy
	self.enemy_character = self.enemy.get_character_body()
	self.sprite = self.enemy_character.get_node("AnimatedSprite2D")	
	
func Exit():
	pass

func update(delta: float) -> void:
	if !player:
		player = get_tree().get_root().get_node("main").get_child(2).get_node("CharacterBody2D") as CharacterBody2D
	if player and enemy:
		move_direction = (player.global_position - self.enemy_character.global_position).normalized()
		if self.enemy_character and self.enemy_character is CharacterBody2D:
			move_direction = (player.global_position - self.enemy_character.global_position).normalized()
			self.enemy_character.velocity = move_direction * self.enemy.speed 
			self.enemy_character.move_and_slide()
		if self.sprite:
			self.sprite.flip_h = player.global_position.x < self.enemy_character.global_position.x