- Edited
I'd like to hear your opinion on this. Every tutorial about statemachines I saw used nodes for each state.
I didn't like adding nodes for each state and decided to derive the state from RefCounted.
According to the docs those get automatically freed once there is no reference to them.
I tested it by adding a print to the function that is being called (forgot its name) before the state gets freed from memory.
And it worked as expected.
I like that I don't have to use nodes and have some type safety because the switch functions needs a PlayerState. No possible typos when passing the statename as string.
Downsides are:
- Can't use export var (not sure if I need them)
- Can cause memory leak if RefCounted doesn't get freed
Need help:
I'd prefer to cache the states I've used. So switching states doesn't create new instances and therefore eliminate memory leaks I guess?
But I haven't figured out if it is possible to pass a type (PlayerState) as argument in the change_state function, then check a dictionary or array if an instance of this type already exists and then create a new one or use the existing one.
The next problem is that when checking any State derived from PlayerState with is
will return PlayerState and not PlayerMoveState for example. So I wouldn't be able to find existing states of that type in a dict.
Do you have any ideas or suggestions?
EDIT: Also does it make sense to use the root node (CharacterBody3D) as statemachine? All tutorials added a childnode to function as statemachine. I don't see why.
Base State:
class_name PlayerState extends RefCounted
var player : CharacterBody3D
func _init(player_instance : CharacterBody3D) -> void:
player = player_instance
func enter():
pass
func update(_delta: float):
pass
func physics_update(_delta: float):
pass
func exit():
pass
Player (StateMachine)
class_name Player extends CharacterBody3D
var current_state : PlayerState
func _ready() -> void:
current_state = PlayerMoveState.new(self)
current_state.enter()
func _process(delta : float):
current_state.update(delta)
func _physics_process(delta: float) -> void:
current_state.physics_update(delta)
func change_state(new_state: PlayerState):
if new_state != null:
if new_state != current_state:
if current_state != null:
current_state.exit()
new_state.enter()
current_state = new_state
else:
push_error("State is null!")