Skip to content

Instantly share code, notes, and snippets.

@NovemberDev
Last active October 5, 2021 12:09
Show Gist options
  • Save NovemberDev/ca8557899f8f360e22873a1f75c290f6 to your computer and use it in GitHub Desktop.
Save NovemberDev/ca8557899f8f360e22873a1f75c290f6 to your computer and use it in GitHub Desktop.
Godot Finite state machine script / class in one file
# godot_finite_state_machine.gd
# by: @november_dev
#
# The finite state machine takes in a number of states and transitions.
#
# A state can contain a function that will be executed or looped while the state is active.
#
# The transition gets a function that returns a boolean truthiness value, which determines
# if the transition should happen or not.
#
# The transition can also get a before_transition and after_transition function.
#
# In this example, some conditions are not given and the function f() is just a shorthand for
# funcref(self, func_name)
#
# Basically, we define states, which execute logic until a condition from a transition is true.
# In this example we go from moving to in air, if we dont touch the floor. If we do touch the floor,
# we go from in air back to moving.
#
#
# Usage:
#
# var fsm = load("res://scripts/fsm.gd").fsm.new()
#
# func _ready():
# fsm.state("moving", f("fsm_moving"), true)
# fsm.state("in_air", f("fsm_in_air"), true)
# fsm.on("entry").transition("moving", f("cond_true"))
#
# #implement your own condition functions
# fsm.on("moving").transition("in_air", f("cond_in_air"))
# fsm.on("in_air").transition("moving", f("cond_on_floor"))
#
#func _physics_process(delta):
# fsm.update()
#
#func f(func_name: String):
# return funcref(self, func_name)
#
#func cond_true():
# return true
class fsm:
var states = {}
var transitions = {}
var current_state = "entry"
var last_inserted_state: String
func _init():
state("entry")
state("anystate")
transitions["anystate"] = []
# call this method during processing
func update():
if (!states[current_state].executed and !states[current_state].loop) or states[current_state].loop:
if states[current_state].logic != null:
states[current_state]["logic"].call_func()
states[current_state].executed = true
handle_transition("anystate")
handle_transition(current_state)
func handle_transition(state: String):
if transitions.has(state):
for s in transitions[state]:
if s.condition != null:
if s["condition"].call_func():
if s.before_transition != null:
s["before_transition"].call_func()
states[current_state].executed = false
current_state = s.to_state
if s.after_transition != null:
s["after_transition"].call_func()
# call this method to record the current state
func on(state: String):
state(state)
last_inserted_state = state
return self
# creates a new state
func state(name: String, logic: FuncRef = null, loop: bool = false):
if !states.has(name):
states[name] = {
executed = false,
logic = logic,
loop = loop
}
return self
# creates a new transition
func transition(to_state: String, condition: FuncRef = null, before_transition: FuncRef = null, after_transition: FuncRef = null):
state(to_state)
if !transitions.has(last_inserted_state):
transitions[last_inserted_state] = []
transitions[last_inserted_state].push_back({
to_state = to_state,
condition = condition,
from_state = last_inserted_state,
after_transition = after_transition,
before_transition = before_transition
})
return self
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment