Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/tavurth/godot-simple-state

A simple Finite State Machine for Godot
https://github.com/tavurth/godot-simple-state

finite-state-machine fsm-library godot godot-engine

Last synced: 6 days ago
JSON representation

A simple Finite State Machine for Godot

Awesome Lists containing this project

README

        

# 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