From 13ae274106ebe8debcebdcea5de997197f867eb2 Mon Sep 17 00:00:00 2001 From: yuki Date: Fri, 14 Nov 2025 15:53:20 -0300 Subject: [PATCH] create abstract state machine class --- scenes/classes/state_machine.gd | 48 +++++++++++++++++++++++++++++ scenes/classes/state_machine.gd.uid | 1 + scenes/classes/state_machine.tscn | 6 ++++ 3 files changed, 55 insertions(+) create mode 100644 scenes/classes/state_machine.gd create mode 100644 scenes/classes/state_machine.gd.uid create mode 100644 scenes/classes/state_machine.tscn diff --git a/scenes/classes/state_machine.gd b/scenes/classes/state_machine.gd new file mode 100644 index 0000000..7e0d627 --- /dev/null +++ b/scenes/classes/state_machine.gd @@ -0,0 +1,48 @@ +## Virtual base class for all nodes that deal directly with states. +## Extend this class and override its methods to implement a state machine. +@abstract class_name StateMachine extends Node + +## The initial state of the state machine. If not set, the first child node is used. +@export var initial_state: State + +## The state machine's current loaded state +@onready var state: State = _get_initial_state() + + +func _ready() -> void: + for state_node: State in find_children("*", "State"): + state_node.finished.connect(_transition_to_next_state) + + await owner.ready + state.enter("") + + +func _unhandled_input(event: InputEvent) -> void: + state.handle_input(event) + + +func _process(delta: float) -> void: + state.update(delta) + + +func _physics_process(delta: float) -> void: + state.physics_update(delta) + + +## Called when initial state is not specified. +## Returns the first child node by default. +## Override if necessary, but don't call it directly. +func _get_initial_state() -> State: + return initial_state if initial_state != null else get_child(0) + + +## Transitions the active state out after receiving a finished signal. +func _transition_to_next_state(target_state_path: String, data: Dictionary = {}) -> void: + if not has_node(target_state_path): + printerr(owner.name + ": Trying to transition to state " + target_state_path + " but it does not exist.") + return + + var previous_state_path: StringName = state.name + state.exit() + state = get_node(target_state_path) + state.enter(previous_state_path, data) diff --git a/scenes/classes/state_machine.gd.uid b/scenes/classes/state_machine.gd.uid new file mode 100644 index 0000000..01f45af --- /dev/null +++ b/scenes/classes/state_machine.gd.uid @@ -0,0 +1 @@ +uid://dqjaxgmyxq3rx diff --git a/scenes/classes/state_machine.tscn b/scenes/classes/state_machine.tscn new file mode 100644 index 0000000..c42124a --- /dev/null +++ b/scenes/classes/state_machine.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://cy4h0xcy2kscg"] + +[ext_resource type="Script" uid="uid://dqjaxgmyxq3rx" path="res://scenes/classes/state_machine.gd" id="1_rnohx"] + +[node name="StateMachine" type="Node"] +script = ExtResource("1_rnohx")