tool class_name State extends Node ## called when state is entered signal state_entered() ## called when state is exited signal state_exited() ## called when state recieves an event while active signal event_received(event) ## called when the state is processing signal state_processing(delta) ## called when the state is physics_processing signal state_physics_processing(delta) ## processing mode enum ProcessMode {IDLE, PHYSICS} ## whether to process transition delays during physics or idle frames export (ProcessMode) var transition_process_mode: int = ProcessMode.PHYSICS ## whether the current state is active var active: bool setget _set_active func _set_active(value: bool): active = value set_process(value) set_physics_process(value) ## all of the state's transitions var _transitions: Array = [] ## queued transition to take var _queued_transition: Transition = null ## time until queued transition is taken var _queued_transition_time: float = 0.0 ## called when building the state chart func _state_init() -> void: _set_active(false) # get references to transitions _transitions.clear() for child in get_children(): if child is Transition: _transitions.append(child as Transition) ## called when state is entered func _state_enter() -> void: _set_active(true) emit_signal("state_entered") # check eventless transitions for transition in _transitions: if not transition.has_event() and transition.evaluate_guard(): # first match is taken _queue_transition(transition) ## called when state is exited func _state_exit() -> void: _set_active(false) emit_signal("state_exited") ## handles given event. returns true if it is consumed func _state_event(event: String) -> bool: if not active: return false # emit event received signal emit_signal("event_received", event) #check for transitions reacting to event for transition in _transitions: if transition.event == event and transition.evaluate_guard(): # first match is taken _queue_transition(transition) return true return false func _process(delta: float) -> void: if Engine.editor_hint: return # emit processing signal emit_signal("state_processing") # process transitions if mode is IDLE if transition_process_mode == ProcessMode.IDLE: _process_transition(delta) func _physics_process(delta: float) -> void: if Engine.editor_hint: return # emit physics processing signal emit_signal("state_processing") # process transitions if mode is PHYSICS if transition_process_mode == ProcessMode.PHYSICS: _process_transition(delta) ## queues a transition to be taken func _queue_transition(transition: Transition) -> void: _queued_transition = transition _queued_transition_time = transition.delay ## checks for and processes queued transition func _process_transition(delta: float) -> void: # check for queued transition if _queued_transition != null: _queued_transition_time -= delta # if ready, handle transition and clear queue if _queued_transition_time <= 0.0: var transition = _queued_transition _queued_transition = null _queued_transition_time = 0.0 _handle_transition(transition, self) ## attempts to take transition func _handle_transition(transition: Transition, source: State) -> void: push_error("state %s cannot handle transitions" % name) func _get_configuration_warning() -> String: return ""