forked from team-sg/hero-mark-2
statecharts ehehehehehe
This commit is contained in:
parent
4d59717b88
commit
6eff1601a9
23 changed files with 895 additions and 2 deletions
104
addons/godot_state_charts/compound_state.gd
Normal file
104
addons/godot_state_charts/compound_state.gd
Normal file
|
@ -0,0 +1,104 @@
|
|||
tool
|
||||
class_name CompoundState, "compound_state.svg"
|
||||
extends State
|
||||
|
||||
## initial state to activate when state is activated
|
||||
export var initial_state: NodePath setget _set_initial_state
|
||||
|
||||
var _active_state: State = null
|
||||
|
||||
onready var _initial_state: State = get_node_or_null(initial_state)
|
||||
|
||||
func _set_initial_state(value: NodePath) -> void:
|
||||
initial_state = value
|
||||
update_configuration_warning()
|
||||
|
||||
func _state_init() -> void:
|
||||
._state_init()
|
||||
|
||||
for child in get_children():
|
||||
if child is State:
|
||||
child._state_init()
|
||||
|
||||
func _state_enter() -> void:
|
||||
._state_enter()
|
||||
|
||||
# activate initial state
|
||||
if _initial_state != null:
|
||||
_active_state = _initial_state
|
||||
_active_state._state_enter()
|
||||
else:
|
||||
push_error("no initial state set for state %s" % name)
|
||||
|
||||
func _state_exit() -> void:
|
||||
# deactivate current state
|
||||
if _active_state != null:
|
||||
_active_state._state_exit()
|
||||
_active_state = null
|
||||
._state_exit()
|
||||
|
||||
func _state_event(event: String) -> bool:
|
||||
if not active:
|
||||
return false
|
||||
|
||||
# forward event to active state
|
||||
if is_instance_valid(_active_state):
|
||||
if _active_state._state_event(event):
|
||||
emit_signal("event_received", event)
|
||||
return true
|
||||
|
||||
# if event not handled by active state, handle here
|
||||
return ._state_event(event)
|
||||
|
||||
func _handle_transition(transition: Transition, source: State) -> void:
|
||||
var target: State = transition.resolve_target()
|
||||
if not target is State:
|
||||
push_error("the target state: %s of transition from state: %s is not a state" % [str(transition.to), source.name])
|
||||
return
|
||||
|
||||
# if direct child, just switch active state
|
||||
if target in get_children():
|
||||
# deactivate current state
|
||||
if is_instance_valid(_active_state):
|
||||
_active_state._state_exit()
|
||||
# activate target state
|
||||
_active_state = target
|
||||
_active_state._state_enter()
|
||||
return
|
||||
|
||||
# if ancestor, activate next state down and let it handle transition further
|
||||
if self.is_a_parent_of(target):
|
||||
# find which child is also ancestor
|
||||
for child in get_children():
|
||||
if child.is_parent_of(target):
|
||||
# change state if necessary
|
||||
if _active_state != child:
|
||||
if is_instance_valid(_active_state):
|
||||
_active_state._state_exit()
|
||||
_active_state = child
|
||||
_active_state._state_enter()
|
||||
child._handle_transition(transition, source)
|
||||
return
|
||||
return
|
||||
|
||||
# target is a cousin, defer to mommy
|
||||
get_parent()._handle_transition(transition, source)
|
||||
|
||||
func _get_configuration_warning() -> String:
|
||||
var warning := ._get_configuration_warning()
|
||||
if not warning.empty():
|
||||
return warning
|
||||
|
||||
if get_child_count() == 0:
|
||||
return "compound states must have at least one child state"
|
||||
|
||||
var child_state = get_node_or_null(initial_state)
|
||||
|
||||
if not is_instance_valid(child_state):
|
||||
return "initial state not found, is the path correct?"
|
||||
if child_state.get_parent() != self:
|
||||
return "initial state must be a direct child of this compound state"
|
||||
if not child_state is State:
|
||||
return "initial state must be a State"
|
||||
|
||||
return ""
|
Loading…
Add table
Add a link
Reference in a new issue