Created
February 15, 2023 08:56
-
-
Save boruok/0e7452011cd9e52615f1001b265c5c47 to your computer and use it in GitHub Desktop.
state machine implementation for Godot Engine
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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