Created
August 27, 2024 21:18
-
-
Save firebelley/96f2f82e3feaa2756fe647d8b9843174 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 CallableStateMachine | |
var state_dictionary = {} | |
var current_state: String | |
func add_states( | |
normal_state_callable: Callable, | |
enter_state_callable: Callable, | |
leave_state_callable: Callable | |
): | |
state_dictionary[normal_state_callable.get_method()] = { | |
"normal": normal_state_callable, | |
"enter": enter_state_callable, | |
"leave": leave_state_callable | |
} | |
func set_initial_state(state_callable: Callable): | |
var state_name = state_callable.get_method() | |
if state_dictionary.has(state_name): | |
_set_state(state_name) | |
else: | |
push_warning("No state with name " + state_name) | |
func update(): | |
if current_state != null: | |
(state_dictionary[current_state].normal as Callable).call() | |
func change_state(state_callable: Callable): | |
var state_name = state_callable.get_method() | |
if state_dictionary.has(state_name): | |
_set_state.call_deferred(state_name) | |
else: | |
push_warning("No state with name " + state_name) | |
func _set_state(state_name: String): | |
if current_state: | |
var leave_callable = state_dictionary[current_state].leave as Callable | |
if !leave_callable.is_null(): | |
leave_callable.call() | |
current_state = state_name | |
var enter_callable = state_dictionary[current_state].enter as Callable | |
if !enter_callable.is_null(): | |
enter_callable.call() |
Can this state machine support binding arguments to a certain state?
I'm new to Godot / GDScript. Coming from C# and Typescript typing is something I hold in high regard, and find some frustrations in GDScripts handling of it. Just tried a small rewrite of this to remove the need for the as Callable
casts, and here's what i came up with.
# honestly just using this class to get around 'no nested typed containers' error.
# Curious if there's a cleaner / less bulky way to do this
class_name State
extends RefCounted
var normal: Callable
var enter: Callable
var leave: Callable
func _init(normal: Callable, enter: Callable, leave: Callable):
self.normal = normal
self.enter = normal
self.leave = normal
class_name CallableStateMachine
var state_dictionary: Dictionary[String, State] = {}
var current_state: String
func add_state(
normal_state_callable: Callable,
enter_state_callable: Callable,
leave_state_callable: Callable
):
state_dictionary[normal_state_callable.get_method()] = \
State.new(normal_state_callable, enter_state_callable, leave_state_callable)
func set_initial_state(state_callable: Callable):
var state_name = state_callable.get_method()
if state_dictionary.has(state_name):
_set_state(state_name)
else:
push_warning("No state with name " + state_name)
func update():
if current_state != "": #null here was a bug. Strings default to "", not null
state_dictionary[current_state].normal.call()
func change_state(state_callable: Callable):
var state_name = state_callable.get_method()
if state_dictionary.has(state_name):
_set_state.call_deferred(state_name)
else:
push_warning("No state with name " + state_name)
func _set_state(state_name: String):
if current_state:
var leave_callable = state_dictionary[current_state].leave
if leave_callable.is_valid():
leave_callable.call()
current_state = state_name
var enter_callable = state_dictionary[current_state].enter
if enter_callable.is_valid():
enter_callable.call()
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Use like so: