Godot Version
Godot Version Godot 4.2.2
Question
Good day Godotians, today I come for help with a state machine set-up not working as I want it to for some reason.
The State machine is node based, only has 2 states right now, and has a few layers so let me go through them first, apologies for how long this whole thing is going to be;
The State Machine script itself:
extends Node
@export var initial_state : State
var current_state : State
var states : Dictionary = {}
func _ready():
for child in get_children():
if child is State:
states[child.name.to_lower()] = child
child.Transition.connect(state_transition)
if initial_state:
initial_state.enter()
current_state = initial_state
func _process(delta):
if current_state:
current_state.state_frame_process(delta)
func _physics_process(delta):
if current_state:
current_state.state_physics_process(delta)
func state_transition(new_state):
if new_state != current_state:
current_state.exit()
current_state = new_state
current_state.enter()
The base State script my other states extend from:
extends Node
class_name State
var state = self
signal Transition(state)
func call_transition():
pass
func enter():
pass
func state_physics_process(_delta):
pass
func state_frame_process(_delta):
pass
func exit():
pass
My Movement State script:
extends State
class_name MoveState
var ACCEL = 300
var SPEED_MAX = 300
var direction = Input.get_axis("move_left", "move_right")
@export var character : CharacterBody2D
@export var animated_sprite : AnimatedSprite2D
func call_transition():
if direction and character.is_on_floor():
Transition.emit(state)
func enter():
pass
func state_physics_process(_delta):
if direction:
character.velocity.x = move_toward(character.velocity.x, SPEED_MAX * direction, ACCEL)
animated_sprite.play("run")
func state_frame_process(_delta):
if direction > 0:
animated_sprite.flip_h = false
elif direction < 0:
animated_sprite.flip_h = true
func exit():
pass
And finally my Idle State script:
extends State
class_name IdleState
var ACCEL = 300
var SPEED_MAX = 300
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
var direction = Input.get_axis("move_left", "move_right")
@export var character : CharacterBody2D
@export var animated_sprite : AnimatedSprite2D
func call_transition():
if !direction and character.is_on_floor():
Transition.emit(state)
func enter():
pass
func state_physics_process(_delta):
character.velocity.x = move_toward(character.velocity.x, 0, ACCEL)
func state_frame_process(_delta):
animated_sprite.play("idle")
func exit():
pass
I’m not getting any errors in the debugger so it isn’t like something’s flat out broken it’s just something in all my logic isn’t connecting.
I placed some prints() in a few of the places that would’ve caught most of my suspicion and it seems like the call_transition function in my state scripts aren’t working as they don’t print anything, so I feel like even beyond that my transition logic and signal usage is overall wrong for what I’m trying to do.
The goal of the transitioning system is for the states themselves to listen for the proper inputs and conditions and then emit a signal passing itself as a variable through the Transition signal, which is connected to the state_transition function renaming the state variable as new_state to be compared to the current_state and then call the exit function on the current_state, declare the new_state as the current_state, and then call the enter function on the new current_state.
I’m not new to programming in object oriented languages, but I am still definitely learning and I didn’t start in Godot either, so I apologize if this problem or what further conversation comes from this is the result of me missing a fundamental property or limitation with what I’m trying to use here, but without any actual errors in the debug I have to simply ask for those with more experience.
Thank you regardless.