Platformer 2.0
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
extends Resource
|
||||
class_name State
|
||||
|
||||
@export var id: StringName
|
||||
|
||||
func enter(_data: Object) -> void:
|
||||
pass
|
||||
|
||||
func exit(_data: Object) -> void:
|
||||
pass
|
||||
|
||||
func process(_data: Object, _delta: float) -> void:
|
||||
pass
|
||||
@@ -0,0 +1 @@
|
||||
uid://b2htg6oquvdho
|
||||
@@ -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)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cp2okhs1ekwad
|
||||
@@ -0,0 +1,15 @@
|
||||
extends Resource
|
||||
class_name StateTransition
|
||||
|
||||
const ANY_STATE: StringName = &"*"
|
||||
|
||||
@export var from: StringName = ANY_STATE
|
||||
@export var to: StringName
|
||||
@export var priority: int = 0
|
||||
@export var condition: TransitionCondition
|
||||
|
||||
func matches_current(current_id: StringName) -> bool:
|
||||
return from == ANY_STATE or from == current_id
|
||||
|
||||
func is_satisfied(data: Object) -> bool:
|
||||
return condition == null or condition.evaluate(data)
|
||||
@@ -0,0 +1 @@
|
||||
uid://e2c8iukkr01l
|
||||
@@ -0,0 +1,18 @@
|
||||
extends Resource
|
||||
class_name TransitionCondition
|
||||
|
||||
var _callable: Callable
|
||||
|
||||
func _init(callable: Callable = Callable()) -> void:
|
||||
_callable = callable
|
||||
|
||||
|
||||
func evaluate(data: Object) -> bool:
|
||||
if _callable.is_valid():
|
||||
var result = _callable.call(data)
|
||||
if result is bool:
|
||||
return result
|
||||
else:
|
||||
push_warning("Transition callable did not return boolean! Returning false.")
|
||||
return false
|
||||
return true
|
||||
@@ -0,0 +1 @@
|
||||
uid://bi3vhketkwgp6
|
||||
Reference in New Issue
Block a user