Platformer 2.0

This commit is contained in:
2026-07-07 19:03:53 -07:00
commit db83628775
23 changed files with 323 additions and 0 deletions
+71
View File
@@ -0,0 +1,71 @@
extends RefCounted
class_name StateMachine
const MIN_PRIORITY = -2147483648
signal state_changed(f_id: StringName, t_id: StringName)
var states: Dictionary[StringName, State] = {}
var transitions: Array[StateTransition] = []
var current_state: State
var _pending_id: StringName = &""
var _pending_priority = MIN_PRIORITY
func setup(state_list: Array[State], transition_list: Array[StateTransition], initial_id: StringName) -> void:
states.clear()
for s in state_list:
if s != null:
states[s.id] = s
transitions = transition_list
current_state = states.get(initial_id)
if current_state == null and not states.is_empty():
current_state = states.values()[0]
push_warning("State machine initial state '%s' not found, falling back to '%s'" % [initial_id, current_state.id])
func process(data: Object, delta: float) -> void:
if current_state == null:
return
current_state.process(data, delta)
_evaluate_transitions(data)
# Escape hatch for an immediate transition
func request_transition(to_id: StringName, priority: int = 999) -> void:
if priority >= _pending_priority:
_pending_id = to_id
_pending_priority = priority
func _evaluate_transitions(data: Object) -> void:
var best_id: StringName = &""
var best_priority: int = MIN_PRIORITY
# Is there a next state pending that isn't our current state?
if _pending_id != &"" and _pending_id != current_state.id and states.has(_pending_id):
best_id = _pending_id
best_priority = _pending_priority
for t in transitions:
# Skip the current state
if not t.matches_current(current_state.id) or t.to == current_state.id:
continue
if not states.has(t.to):
push_warning("StateMachine: transition targets unknown state '%s'" % t.to)
continue
if t.priority < best_priority:
continue
if t.is_satisfied(data):
best_id = t.to
best_priority = t.priority
_pending_id = &""
_pending_priority = MIN_PRIORITY
if best_id != &"" and best_id != current_state.id:
var from_id = current_state.id
current_state.exit(data)
current_state = states[best_id]
current_state.enter(data)
state_changed.emit(from_id, current_state.id)