Awesome
Godot Simple State
A clean and easy to use Finite State Machine (FSM) for Godot 3.x
<a id="org4aefb14"></a>
Usage
-
Install the plugin
-
Enable the plugin
-
Add a
<img width="342" alt="Screenshot 2022-02-19 at 12 36 45" src="https://user-images.githubusercontent.com/100964/154795429-effb016d-1d2b-4719-b4f9-8dc14f6e23c1.png">SateMachine
node to your character -
Add any type of
<img width="343" alt="Screenshot 2022-02-19 at 12 36 30" src="https://user-images.githubusercontent.com/100964/154795416-322c85d7-8557-42a3-9b49-e3607a798512.png">Node
to theStateMachine
as a child to create a new script -
Attach a script to the node
-
Now at runtime you can change to a different state using
$StateMachine.goto("state")
Example
The example project contains two states, idle
and attack
.
The project will switch between each state automatically every 3 seconds.
State functionality
The state has a few functionalities, here is an example state:
extends Node2D
var States
var Host
func _state_enter(arg or not):
pass
func _state_exit():
pass
If you call await
in _state_exit
the StateMachine
will wait for your await
to finish before entering the new state.
This is also true for _state_enter
or other state functions.
func _state_exit():
await get_tree().create_timer(1).timeout
Note: Exit state
state
will change to _exit
when the state machine is exiting.
Your state will also be queue-freed.
If running a long while loop in your state logic, be sure to check for States.is_current()
Reference
StateMachine
signal
state_changed(new_state)
Emitted whenever the StateMachine
changes state (but before _state_enter
is called)
goto(state_name: String, args = null)
change the state
args
can be any or undefined
When an arg is passed, the argument will be pushed to the _state_enter
function.
StateMachine.goto("attack")
StateMachine.goto("attack", some_character)
StateMachine.goto("attack", [some_character_a, some_character_b])
The last example would call this function in the attack
state:
func _state_enter(some_characters: Array):
...
call(method: String, args = null)
call a function on the current state (if exists)
StateMachine.call("some_method")
StateMachine.call("some_method", my_argument)
StateMachine.call("some_method", [my_arguments])
now(state: String)
Returns true if the current state matches state
if States.now("afraid"):
# keep running away instead of stopping to look at something
has(state: String)
Returns true if <state> exists in our state tree
if States.has("some-other-state"):
# Do something
is_current()
Returns true only when called from a function inside the current state
if States.is_current():
This can only be printed in the current state
In any other state this will never be printed
restart(arg: any or none)
Restarts the current state This only calls "_state_enter" again it does not reset any variables
State
_state_enter(args or not)
will be called when the state is entered (each time)
An argument is only passed if one was passed. (StateMachine.goto("state", arg)
)
_state_exit()
will be called when the state is left (each time)
If the following variables exist on your state, they will be injected with dependencies as follows:
Host
is the NodePath
input into StateMachine
i.e. your character controller
States
is the StateMachine
If they do not exist on your state, nothing will be injected.
Signals
You can connect signals directly to the StateMachine
node using the following style:
They will be then automatically sent to the current active state if that state has the handler function defined.
<a href="https://www.buymeacoffee.com/tavurth" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>