Attack State does not change the current state

Godot Version

Godot 4.3

Question

I am creating a behavior tree for a base enemy scene. It’s organized by one state machine with a few child state nodes under it.

So for the Patrol and Aggressive states, they transition to other states well. But, I am finding that the Attack state is having trouble with it. I am not making much progress on it, so I need help finding why the state doesn’t change.

The state machine has a function, change_state(new_state), that calls upon the exit function of the previous state and the enter function of the new state.

class_name State_Machine
extends Node

signal transitioned(state)

@export var starting_state: State
var current_state: State

func init(parent: Node3D) -> void:
	for child in get_children():
		child.parent = parent
	
	change_state(starting_state)

func change_state(new_state: State) -> void:
	if current_state:
		current_state.exit()
	current_state = new_state
	current_state.enter()
	transitioned.emit(current_state)

The attack state inherits an abstract state class with empty functions to be filled by custom logic

extends State

signal attack(data: Attack_Stats)

@export var attack_data: Attack_Stats
@export var next_attack: State
@export var return_state: State
@onready var state_machine = get_parent()

func enter() -> void:
	print_debug("attacking player");
	change_anim.emit(attack_data.animation_name)
	play_audio.emit(attack_data.SFX)
	attack.emit(attack_data)

func _on_animation_player_animation_finished(anim_name: StringName) -> void:
	if anim_name == attack_data.animation_name:
		# Grab the new player position
		var player_position = parent.player_target.global_position
		# if close enough try another attack
		if parent.check_target_reached(player_position):
			state_machine.change_state(next_attack)
		# if not close enough then change state
		else:
			state_machine.change_state(return_state)

And in testing, once the attack animation is over, it should transition to itself or transition to the aggressive state in the tree. I could call the enter function, but I want to leave room to create child states that handle other attacks that could come next in a combo.

So is there anything people can notice about the code that may cause a failure in changing states?

Is it possible it isn’t unwinding from the initial call to change_state()?
Since the enter function in the attack state will call change_state() again (via the animation finished signal).

Otherwise how sure are you that _on_animation_player_animation_finished() is being called and how sure are you of the values of next_attack, next_state (and does the code get to either of those change_state calls)?

From the debugs I am trying, after the enter() function, _on_animation_player_animation_finished() does not seem to trigger. The animation moves back to the animation set in aggressive, but change state does not get invoked again.

I couldn’t show it in the original post, but this is the variables set in the inspector

All variables are showing up as non-null values in the debug:

Entering patrol.
   At: res://States/Patrol.gd:8:enter()
Entering aggressive.
   At: res://States/Aggressive.gd:8:enter()
attacking player
   At: res://States/Attack.gd:11:enter()
Attack:<Node#44358960533>Aggressive:<Node#44342183332><Resource#-9223371993972210256>
   At: res://States/Attack.gd:12:enter()

The first thing to check then is the connection to the animation_finished signal.
If you connect via the editor then there should be a green mark beside the function in the editor:


If you connect via code then make sure that is valid and the code is being reached.

Put a print statement at the beginning of the animation_finished function printing out the anim_name and the attack_data.animation_name.
If you don’t see the output then for sure the connection is not set.

The connection looks correct. We are connecting via inspector. I’m looking at the animation player to see if something is wrong there.

I’m not sure what else could be wrong here.