-
-
Save firebelley/96f2f82e3feaa2756fe647d8b9843174 to your computer and use it in GitHub Desktop.
| 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() |
Heya, if you're still working with this I'm running into an issue where the "enter" and "leave" callables are still being called when using await timer randf_range to determine when to transition. Any suggestions? Found the problem, I had another part of the script executing functions that shouldn't have been executed.
@mbnewsom All your code can be in a single script. I've updated it below, also fixed the typo in the State._init declaration.
I'll probably update this code further once I test it with the new variadic arguments, so we will be allowed to declare this as a single external Node, extend its script to declare the states and give arguments to .update() and .state_change(), allowing transient variables, like delta and controller inputs, being passed into, instead of holding global references, to access these values inside the state functions.
# callable_state_machine.gd
class_name CallableStateMachine
class_name State
var normal: Callable
var enter: Callable
var leave: Callable
func _init(normal: Callable, enter: Callable, leave: Callable):
self.normal = normal
self.enter = enter
self.leave = leave
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()
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 Callablecasts, and here's what i came up with.