# Godot Simple State A clean and easy to use Finite State Machine (FSM) for Godot 3.x [![img](https://awesome.re/mentioned-badge.svg)](https://github.com/godotengine/awesome-godot) ![img](https://img.shields.io/github/license/tavurth/godot-simple-state.svg) ![img](https://img.shields.io/github/repo-size/tavurth/godot-simple-state.svg) ![img](https://img.shields.io/github/languages/code-size/tavurth/godot-simple-state.svg) # Usage 1. Install the plugin 2. Enable the plugin 3. Add a `SateMachine` node to your character Screenshot 2022-02-19 at 12 36 45 4. Add any type of `Node` to the `StateMachine` as a child to create a new script Screenshot 2022-02-19 at 12 36 30 5. Attach a script to the node 6. 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: ```ddscript 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. ```gdscript 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. ```gdscript 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: ```gdscript func _state_enter(some_characters: Array): ... ``` ### `call(method: String, args = null)` call a function on the current state (if exists) ```gdscript 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` ```gdscript if States.now("afraid"): # keep running away instead of stopping to look at something ``` ### `has(state: String)` Returns true if exists in our state tree ```gdscript if States.has("some-other-state"): # Do something ``` ### `is_current()` Returns true only when called from a function inside the current state ```gdscript 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: Screenshot 2022-02-19 at 13 00 38 They will be then automatically sent to the current active state if that state has the handler function defined. Buy Me A Coffee