Skip to content

Instantly share code, notes, and snippets.

@boruok
Created February 15, 2023 08:56
Show Gist options
  • Save boruok/0e7452011cd9e52615f1001b265c5c47 to your computer and use it in GitHub Desktop.
Save boruok/0e7452011cd9e52615f1001b265c5c47 to your computer and use it in GitHub Desktop.
state machine implementation for Godot Engine
class_name StateMachine extends Node
signal current_state_changed(to)
var _current_state_name : String
var _current_state : State
var _config := {
"target" : null,
"current_state" : "",
"states" : {},
"transitions" : {},
}
func transition(name: String) -> void:
if _config.transitions.has(_current_state_name):
if _config.transitions[_current_state_name].has(name):
if _current_state:
_current_state._on_leave()
set_current_state(name)
emit_signal("current_state_changed", name)
return
set_current_state(name)
emit_signal("current_state_changed", name)
else:
print_debug("%s failed to traslate: transition from '%s' to '%s' doesn't allowed." % [_config.target.get_class(), _current_state_name, name])
else:
print_debug("%s failed to traslate: '%s' doesn't have transitions" % [_config.target.get_class(), _current_state_name])
func add_state(name: String, state: State, override:=false) -> void:
if _config.states.has(name):
if !override:
print_debug("%s failed to add a new state: state already exists." % _config.target.get_class())
return
_setup_new_state(name, state)
else:
_setup_new_state(name, state)
func add_transition(name: String, list: Array, override:=false) -> void:
if _config.transitions.has(name):
if override:
_config.transitions[name] = list
else:
print_debug("%s failed to add a new transition: transition already exists." % _config.target.get_class())
else:
_config.transitions[name] = list
func set_current_state(name: String) -> void:
if _config.states.has(name):
_current_state_name = name
_current_state = _config.states[name]
_current_state._on_enter()
else:
print_debug("%s failed to set current state: '%s' state in config table" % [_config.target.get_class(), name])
func get_current_state() -> State:
return _current_state
func get_current_state_name() -> String:
return _current_state_name
func get_class() -> String:
return "StateMachine"
func update(delta: float) -> void:
_current_state.update(delta)
func physics_update(delta: float) -> void:
_current_state.physics_update(delta)
func input(event: InputEvent) -> void:
_current_state.input(event)
func _setup_new_state(name: String, state: State) -> void:
_config.states[name] = state
_config.states[name].sm = weakref(self)
_config.states[name].target = _config.target
func init(config: Dictionary) -> void:
_config.target = config.target
for state in config.states:
add_state(state, config.states[state])
for transition in config.transitions:
add_transition(transition, config.transitions[transition])
set_current_state(config.current_state)
class State:
var target : Object
var sm : Node
func update(delta: float) -> void: pass
func physics_update(delta: float) -> void: pass
func input(event: InputEvent) -> void: pass
func _on_enter() -> void: pass
func _on_leave() -> void: pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment