Platformer 2.0
This commit is contained in:
@@ -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)
|
||||
Reference in New Issue
Block a user