#State machine transition isnt working
14 messages · Page 1 of 1 (latest)
this is my base state class
the fsm
the idle state
and the run state
i would also like help with how to get movment working on the run state since im extending from state i dont have the code to work with velocity.x or is_on_floor functions unless im wrong
also if my terminlogy is wrong its cause im still new
Glancing over the code it seems that at the moment nothing really runs, except the _ready() function of your FiniteStateMachine class and then the .Enter() function of the initial_state.
Running stuff each Frame
If you want to run code each frame then you need a _physics_process() and/or _process() somewhere inside the FiniteStateMachine class.
In the State you don´t want to overwrite_physics_process() and/or _process() directly, because then each state would just run all the time each frame. Instead you have some function like update() or physics_update() that you define that you will call inside _process() of the FiniteStateMachine. The Statemachine only lets the current_state run each frame then.
From your State Class it seems like the Update() function could be something that you want to run each frame.
That means in your FiniteStateMachine script you´d have something like this:
extends Node
class_name FiniteStateMachine
...
var current_state:State
...
func _ready():
...
func change_state(...):
...
func _process(delta: float):
current_state.Update(delta)
Another thing i noticed is, that your State class has the 3 functions Enter(), Exit() and Update(), but not the function _physics_process_update() that you defined in the run state. I guess this is the function that you want to run periodically inside with _physics_process.
Then i would add that function definition inside your State class and add the line to run it inside the Statemachine too.
# // fsm.gd
extends Node
class_name FiniteStateMachine
...
func _physics_process(delta: float):
current_state._physics_process_update(delta)
If you want a certain type/class of State to run inside the Statemachine, id have them use all the same interface (the same function names), because in the end the Statemachine will dictate which functions the states call each frame. And if it doesnt know how they are called or they are called differently, youll have some troubles.
Making the character move
To make the Character move you need to have a reference to it.
I can recommend this tutorial: (https://www.gdquest.com/tutorial/godot/design-patterns/finite-state-machine/)
In their PlayerState class they get a reference with player = owner as Player.
If the Player node is the root of the scene, then it is the owner of your State Node in this case, so it is one easy way to get a reference to it.
With type casting usingas Player , you´ll get the autocompletion of all the properties and methods of your Characterbody2D (and the rest of the Player class).
You can then move the player inside your State with player.move_and_slide() or anything.
class_name PlayerState extends State
...
var player: Player
func _ready() -> void:
await owner.ready
player = owner as Player
Instead of using owner you could let the Statemachine script give its children (the States) a reference to the player/character node (same place where you connect the signals etc.).
Note: In their tutorial PlayerState is just a new generic type of State which has the same interface, but just the player reference added. They then extend from that PlayerState for their Idle, Run etc. state.
You can implement all that stuff with the reference inside your State class instead and extend the States like you do it right now anyway if you want.
But to actually answer the question about the transition in a tldr way:
- Your current state is the
IdleState where you want to start transition into theRunstate inside theUpdate()function by checking for an Input - Your transition doesnt work , since you never call
Update()anywhere - You want to call it inside
_process()inside yourFiniteStatemachine, where you´ll run thecurrent_state.Update(delta)