State machine causing character to not move when you spam attack enough

Godot Version

4.2.2

Question

I have an issue with my game using a state machine. All my characters have 5 states. Idle, Walk, Attack, Special, and Hitstun. After using your special, if you hold down and spam attack, all states stop working. What could be causing this? Here’s all my relevant code.

Special attack

extends State
class_name BobSpecial1

@export var Bob : CharacterBody2D
@export var fsm : StateMachine

func Enter():
	Bob.special()

func Update(delta):
	if PlayerVariables.p1_knockback == true:
		fsm.force_change_state("Hitstun")

func _on_animation_player_animation_finished(anim_name):
	if anim_name == "Dash Attack" and !Input.get_axis("p1_Left", "p1_Right"):
		fsm.change_state(self, "Idle")
	if anim_name == "Dash Attack" and Input.get_axis("p1_Left", "p1_Right"):
		fsm.change_state(self, "Walk")
	if anim_name == "Dash Attack" and Input.is_action_just_pressed("p1_Attack") and !Input.is_action_pressed("p1_Down"):
		fsm.change_state(self, "Attack")
	if anim_name == "Dash Attack" and Input.is_action_pressed("p1_Down") and Input.is_action_just_pressed("p1_Attack"):
		fsm.change_state(self, "Special")

Idle state

extends State
class_name BobIdle1

@export var Bob : CharacterBody2D
@export var fsm : StateMachine

func Enter():
	Bob.idle()

func Update(delta):
	if Input.get_axis("p1_Left", "p1_Right"):
		fsm.change_state(self, "Walk")
	
	if Input.is_action_just_pressed("p1_Attack") and !Input.is_action_pressed("p1_Down"):
		fsm.change_state(self, "Attack")
	
	if Input.is_action_pressed("p1_Down") and Input.is_action_just_pressed("p1_Attack"):
		fsm.change_state(self, "Special")
	
	if PlayerVariables.p1_knockback == true:
		fsm.force_change_state("Hitstun")

Hitstun state

extends State
class_name BobHitstun1

@export var Bob : CharacterBody2D
@export var fsm : StateMachine

func Enter():
	Bob.hitstun()

func Update(delta):
	if PlayerVariables.p1_knockback == true:
		fsm.force_change_state("Hitstun")

func _on_animation_player_animation_finished(anim_name):
	if anim_name == "Hitstun" and !Input.get_axis("p1_Left", "p1_Right"):
		fsm.change_state(self, "Idle")
	if anim_name == "Hitstun" and Input.get_axis("p1_Left", "p1_Right"):
		fsm.change_state(self, "Walk")
	if anim_name == "Hitstun" and Input.is_action_pressed("p1_Down") and Input.is_action_just_pressed("p1_Attack") and !Input.get_axis("p1_Left", "p1_Right"):
		fsm.change_state(self, "Special")
	if anim_name == "Hitstun" and Input.is_action_just_pressed("p1_Attack") and !Input.is_action_pressed("p1_Down"):
		fsm.change_state(self, "Attack")

Walk state

extends State
class_name BobWalk1

@export var Bob : CharacterBody2D
@export var fsm : StateMachine

func Physics_Update(delta):
	var direction = Input.get_axis("p1_Left", "p1_Right")
	Bob.walk(direction)
	
	if direction == 0:
		fsm.change_state(self, "Idle")
	
	if Input.is_action_just_pressed("p1_Attack") and !Input.is_action_pressed("p1_Down"):
		fsm.change_state(self, "Attack")
	
	if Input.is_action_pressed("p1_Down") and Input.is_action_just_pressed("p1_Attack"):
		fsm.change_state(self, "Special")
	
	if PlayerVariables.p1_knockback == true:
		fsm.force_change_state("Hitstun")

Attack state

extends State
class_name BobAttack1

@export var Bob : CharacterBody2D
@export var fsm : StateMachine

func Enter():
	Bob.attack()

func Update(delta):
	if PlayerVariables.p1_knockback == true:
		fsm.force_change_state("Hitstun")

func _on_animation_player_animation_finished(anim_name):
	if anim_name == "Light" and !Input.get_axis("p1_Left", "p1_Right"):
		fsm.change_state(self, "Idle")
	if anim_name == "Light" and Input.get_axis("p1_Left", "p1_Right"):
		fsm.change_state(self, "Walk")
	if anim_name == "Light" and Input.is_action_pressed("p1_Down") and Input.is_action_just_pressed("p1_Attack") and !Input.get_axis("p1_Left", "p1_Right"):
		fsm.change_state(self, "Special")
	if anim_name == "Light" and Input.is_action_just_pressed("p1_Attack") and !Input.is_action_pressed("p1_Down"):
		fsm.change_state(self, "Attack")

State machine

extends Node
class_name StateMachine

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

func _ready():
	for child in get_children():
		if child is State:
			states[child.name.to_lower()] = child
			child.state_transition.connect(change_state)
	if initial_state:
		initial_state.Enter()
		current_state = initial_state

func _process(delta):
	if current_state:
		current_state.Update(delta)

func _physics_process(delta):
	if current_state:
		current_state.Physics_Update(delta)

func force_change_state(new_state : String):
	var newState = states.get(new_state.to_lower())
	
	if !newState:
		return
	
	if current_state == newState:
		return
	
	if current_state:
		var exit_callable = Callable(current_state, "Exit")
		exit_callable.call_deferred()
	
	newState.Enter()
	
	current_state = newState

func change_state(source_state : State, new_state_name : String):
	if source_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

Relevant character (Bob) script

func idle():
	anim.play("Idle")
	velocity.x = move_toward(velocity.x, 0, SPEED)

func special():
	if can_dash == true:
		anim.play("Dash Attack")
		timer.start()
		can_dash = false
		dash_timer.start()
		velocity.x = move_toward(velocity.x, 0, SPEED)

func walk(direction):
	velocity.x = direction * SPEED
	anim.play("Walk")
	if direction > 0:
		anim_sprite.scale.x = 1
		PlayerVariables.p1_dir = 1
	if direction < 0:
		anim_sprite.scale.x = -1
		PlayerVariables.p1_dir = -1

func attack():
	anim.play("Light")
	velocity.x = move_toward(velocity.x, 0, SPEED)

func hitstun():
	velocity.y = -500
	velocity.x = 100 * PlayerVariables.p2_dir
	anim.play("Hitstun")
	PlayerVariables.p1_knockback = false