statecharts ehehehehehe

This commit is contained in:
Haze Weathers 2023-04-13 14:24:41 -04:00
parent 4d59717b88
commit 6eff1601a9
23 changed files with 895 additions and 2 deletions

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<rect id="Artboard1" x="0" y="0" width="32" height="32" style="fill:none;"/>
<g id="Artboard11" serif:id="Artboard1">
<g transform="matrix(1.03705,0,0,1.03705,-0.460588,-0.659827)">
<g id="BG">
<path d="M30.337,8.833C30.337,4.841 27.096,1.601 23.104,1.601L8.64,1.601C4.649,1.601 1.408,4.841 1.408,8.833L1.408,23.297C1.408,27.288 4.649,30.529 8.64,30.529L23.104,30.529C27.096,30.529 30.337,27.288 30.337,23.297L30.337,8.833Z" style="fill:none;stroke:rgb(225,142,57);stroke-width:0.96px;"/>
</g>
</g>
<g id="AnimationTreeState">
<g transform="matrix(3.01177,0,0,3.01177,-34.5681,-33.1274)">
<circle cx="16.79" cy="16.312" r="3.319" style="fill:rgb(225,142,57);"/>
</g>
<g transform="matrix(1,0,0,1,-0.944123,0.510573)">
<path d="M12.988,9.407L14.259,22.064L15.427,22.185L15.484,19.654L17.723,19.607L17.7,21.031L18.427,20.976L18.583,18.442L15.48,18.154L15.515,14.006L20.744,13.909L20.738,16.136L21.79,16.077L21.992,12.615L15.399,12.643L14.958,9.391L12.988,9.407Z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/animation_tree_state.svg-b99077fc178cfa1e23b2c854c7735c4a.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_state_charts/animation_tree_state.svg"
dest_files=[ "res://.import/animation_tree_state.svg-b99077fc178cfa1e23b2c854c7735c4a.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -0,0 +1,23 @@
tool
class_name AtomicState, "atomic_state.svg"
extends State
func _handle_transition(transition: Transition, source: State) -> void:
# resolve target state
var target = 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
# atomic states can't transition, gotta ask mommy
get_parent()._handle_transition(transition, source)
func _get_configuration_warning() -> String:
var warning := ._get_configuration_warning()
if not warning.empty():
return warning
for child in get_children():
if not child is Transition:
return "atomic states cannot have children other than transitions"
return ""

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<rect id="Artboard1" x="0" y="0" width="32" height="32" style="fill:none;"/>
<g id="Artboard11" serif:id="Artboard1">
<g transform="matrix(1.03705,0,0,1.03705,-0.460588,-0.659827)">
<g id="BG">
<path d="M30.337,8.833C30.337,4.841 27.096,1.601 23.104,1.601L8.64,1.601C4.649,1.601 1.408,4.841 1.408,8.833L1.408,23.297C1.408,27.288 4.649,30.529 8.64,30.529L23.104,30.529C27.096,30.529 30.337,27.288 30.337,23.297L30.337,8.833Z" style="fill:none;stroke:rgb(225,142,57);stroke-width:0.96px;"/>
</g>
</g>
<g transform="matrix(3.01177,0,0,3.01177,-34.5681,-33.1274)">
<g id="AtomicState">
<circle cx="16.79" cy="16.312" r="3.319" style="fill:rgb(225,142,57);"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/atomic_state.svg-5ab16e5747cef5b5980c4bf84ef9b1af.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_state_charts/atomic_state.svg"
dest_files=[ "res://.import/atomic_state.svg-5ab16e5747cef5b5980c4bf84ef9b1af.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View 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 ""

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<rect id="Artboard1" x="0" y="0" width="32" height="32" style="fill:none;"/>
<g id="Artboard11" serif:id="Artboard1">
<g transform="matrix(1.03705,0,0,1.03705,-0.460588,-0.659827)">
<g id="BG">
<path d="M30.337,8.833C30.337,4.841 27.096,1.601 23.104,1.601L8.64,1.601C4.649,1.601 1.408,4.841 1.408,8.833L1.408,23.297C1.408,27.288 4.649,30.529 8.64,30.529L23.104,30.529C27.096,30.529 30.337,27.288 30.337,23.297L30.337,8.833Z" style="fill:none;stroke:rgb(225,142,57);stroke-width:0.96px;"/>
</g>
</g>
<g id="CompoundState">
<path d="M7.984,22.271L16.112,8.238L24.694,22.425L7.984,22.271Z" style="fill:none;stroke:rgb(225,142,57);stroke-width:2px;"/>
<g transform="matrix(1.36246,0,0,1.36246,-18.1682,-4.24482)">
<circle cx="19.207" cy="19.263" r="4.404" style="fill:rgb(225,142,57);"/>
</g>
<g transform="matrix(1.36246,0,0,1.36246,-2.16822,-4.24482)">
<circle cx="19.207" cy="19.263" r="4.404" style="fill:rgb(225,142,57);"/>
</g>
<g transform="matrix(1.36246,0,0,1.36246,-10.1682,-17.6299)">
<circle cx="19.207" cy="19.263" r="4.404" style="fill:rgb(225,142,57);"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/compound_state.svg-84780d78ec1f15e1cbb9d20f4df031a7.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_state_charts/compound_state.svg"
dest_files=[ "res://.import/compound_state.svg-84780d78ec1f15e1cbb9d20f4df031a7.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -0,0 +1,10 @@
tool
extends EditorPlugin
# plugin initialization
func _enter_tree() -> void:
pass
# plugin cleanup
func _exit_tree() -> void:
pass

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<rect id="Artboard1" x="0" y="0" width="32" height="32" style="fill:none;"/>
<g id="Artboard11" serif:id="Artboard1">
<g transform="matrix(1.03705,0,0,1.03705,-0.460588,-0.659827)">
<g id="BG">
<path d="M30.337,8.833C30.337,4.841 27.096,1.601 23.104,1.601L8.64,1.601C4.649,1.601 1.408,4.841 1.408,8.833L1.408,23.297C1.408,27.288 4.649,30.529 8.64,30.529L23.104,30.529C27.096,30.529 30.337,27.288 30.337,23.297L30.337,8.833Z" style="fill:none;stroke:rgb(225,142,57);stroke-width:0.96px;"/>
</g>
</g>
<g id="HistoryState">
<g transform="matrix(1,0,0,1,0.326002,-0.0776194)">
<path d="M7.731,16.235C7.731,11.827 11.31,8.248 15.718,8.248C20.127,8.248 23.706,11.827 23.706,16.235C23.706,20.644 20.127,24.222 15.718,24.222C13.665,24.222 11.792,23.446 10.377,22.171" style="fill:none;stroke:rgb(225,142,57);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0,0,1,0.465717,0)">
<path d="M7.731,16.235L10.089,16.228L7.707,18.393L5.332,16.235L7.731,16.235Z" style="fill:none;stroke:rgb(225,142,57);stroke-width:2px;"/>
</g>
<g transform="matrix(1,0,0,1,0.294954,0.0776194)">
<path d="M15.646,12.205L15.568,16.908L18.021,18.771" style="fill:none;stroke:rgb(225,142,57);stroke-width:2px;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/history_state.svg-7ed355ddc4d844fa3139e70c23187edd.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_state_charts/history_state.svg"
dest_files=[ "res://.import/history_state.svg-7ed355ddc4d844fa3139e70c23187edd.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -0,0 +1,53 @@
tool
class_name ParallelState, "parallel_state.svg"
extends State
var _sub_states: Array = []
func _state_init() -> void:
._state_init()
for child in get_children():
if child is State:
_sub_states.append(child)
child._state_init()
func _state_enter() -> void:
._state_enter()
# enter all children
for child in _sub_states:
child._state_enter()
func _state_exit() -> void:
# exit all children
for child in _sub_states:
child._state_exit()
._state_exit()
func _state_event(event: String) -> bool:
if not active:
return false
# forward to all children
var handled := false
for child in _sub_states:
var child_handled = child._state_event(event)
handled = handled or child_handled
# if child handled event, no more touchy
if handled:
emit_signal("event_received", event)
return true
# otherwise handle ourselves
return ._state_event(event)
func _get_configuration_warning() -> String:
var warning := ._get_configuration_warning()
if not warning.empty():
return warning
if get_child_count() == 0:
return "parallel states should have at least one child state"
return ""

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<rect id="Artboard1" x="0" y="0" width="32" height="32" style="fill:none;"/>
<g id="Artboard11" serif:id="Artboard1">
<g transform="matrix(1.03705,0,0,1.03705,-0.460588,-0.659827)">
<g id="BG">
<path d="M30.337,8.833C30.337,4.841 27.096,1.601 23.104,1.601L8.64,1.601C4.649,1.601 1.408,4.841 1.408,8.833L1.408,23.297C1.408,27.288 4.649,30.529 8.64,30.529L23.104,30.529C27.096,30.529 30.337,27.288 30.337,23.297L30.337,8.833Z" style="fill:none;stroke:rgb(225,142,57);stroke-width:0.96px;"/>
</g>
</g>
<g id="ParallelState">
<g transform="matrix(1.36246,0,0,1.36246,-10.1682,-18.2448)">
<circle cx="19.207" cy="19.263" r="4.404" style="fill:rgb(225,142,57);"/>
</g>
<g transform="matrix(1,0,0,1,-0.0397943,-0.229175)">
<path d="M4.306,16.267L27.54,16.341" style="fill:none;stroke:rgb(225,142,57);stroke-width:2px;"/>
</g>
<g transform="matrix(1.36246,0,0,1.36246,-10.1682,-2.24482)">
<circle cx="19.207" cy="19.263" r="4.404" style="fill:rgb(225,142,57);"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/parallel_state.svg-33f40e94bafae79f072d67563e0adcd3.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_state_charts/parallel_state.svg"
dest_files=[ "res://.import/parallel_state.svg-33f40e94bafae79f072d67563e0adcd3.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -0,0 +1,7 @@
[plugin]
name="Godot State Charts"
description="A simple, yet powerful state charts library for Godot"
author="derkork"
version="0.0.1"
script="godot_state_charts.gd"

View file

@ -0,0 +1,126 @@
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 ""

View file

@ -0,0 +1,51 @@
tool
class_name StateChart, "state_chart.svg"
extends Node
# root state of the state chart
var _state: State = null
# values available to expression guards
var _expression_properties: Dictionary = {}
func _ready() -> void:
if Engine.editor_hint:
return
# make sure only one child exists
if get_child_count() != 1:
push_error("StateChart must have exactly one child")
return
# verify child is a State
var child = get_child(0)
if not child is State:
push_error("StateChart's child must be a State")
return
# initialize states
_state = child as State
_state._state_init()
# enter root state
_state._state_enter()
## sends an event to be propagated through the states
func send_event(event: String) -> void:
if not is_instance_valid(_state):
push_error("StateChart is not initialized properly")
return
_state._state_event(event)
## sets a property available to guard expressions in transitions
func set_expression_property(property: String, value) -> void:
_expression_properties[property] = value
func _get_configuration_warning() -> String:
if get_child_count() != 1:
return "StateChart must have exactly one child"
elif not get_child(0) is State:
return "StateChart's child must be a State"
else:
return ""

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<rect id="Artboard1" x="0" y="0" width="32" height="32" style="fill:none;"/>
<g id="Artboard11" serif:id="Artboard1">
<g transform="matrix(1.03705,0,0,1.03705,-0.460588,-0.659827)">
<g id="BG">
<path d="M30.337,8.833C30.337,4.841 27.096,1.601 23.104,1.601L8.64,1.601C4.649,1.601 1.408,4.841 1.408,8.833L1.408,23.297C1.408,27.288 4.649,30.529 8.64,30.529L23.104,30.529C27.096,30.529 30.337,27.288 30.337,23.297L30.337,8.833Z" style="fill:none;stroke:rgb(225,142,57);stroke-width:0.96px;"/>
</g>
</g>
<g id="Statechart">
<g transform="matrix(0.672421,0,0,0.672421,-1.95754,-0.281501)">
<path d="M26.032,10.926C26.032,8.533 24.089,6.591 21.696,6.591L13.025,6.591C10.632,6.591 8.689,8.533 8.689,10.926L8.689,20.247C8.689,22.639 10.632,24.582 13.025,24.582L21.696,24.582C24.089,24.582 26.032,22.639 26.032,20.247L26.032,10.926Z" style="fill:rgb(225,142,57);stroke:rgb(225,142,57);stroke-width:2.97px;"/>
</g>
<g transform="matrix(0.851682,0,0,0.851682,5.75568,7.00772)">
<path d="M26.032,10.926C26.032,8.533 24.089,6.591 21.696,6.591L13.025,6.591C10.632,6.591 8.689,8.533 8.689,10.926L8.689,20.247C8.689,22.639 10.632,24.582 13.025,24.582L21.696,24.582C24.089,24.582 26.032,22.639 26.032,20.247L26.032,10.926Z" style="fill:rgb(225,142,57);stroke:rgb(225,142,57);stroke-width:2.35px;"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/state_chart.svg-5c268dd045b20d73dfacd5cdf7606676.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_state_charts/state_chart.svg"
dest_files=[ "res://.import/state_chart.svg-5c268dd045b20d73dfacd5cdf7606676.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -0,0 +1,88 @@
tool
class_name Transition, "transition.svg"
extends Node
## cyclic reference workarounds :/
var _State = load("res://addons/godot_state_charts/state.gd")
var _StateChart = load("res://addons/godot_state_charts/state_chart.gd")
## state to transition to
export var to: NodePath
## event to react to for transition
export var event: String
## delay before taking transition
export var delay: float = 0.0
## expression to determine whether to take transition
## if it returns true the transition will be taken
## expression properties added via the StateChart are available here
## if states are listed in `monitored_states`, they will be available as
## boolean properties named "[state]_active"
export (String, MULTILINE) var guard_expression: String
## states to check if active
## they are available in the guard expression as bools named "[state]_active"
export (Array, NodePath) var checked_states: Array = []
## returns true if the transition has an event to react to
func has_event() -> bool:
return event != null and not event.empty()
## returns the target state
func resolve_target():
if to == null or to.is_empty():
return null
var target = get_node_or_null(to)
if target is _State:
return target
return null
## returns true if the transition should be taken at this time
func evaluate_guard() -> bool:
# return true if there is no guard
if guard_expression == null or guard_expression.empty():
return true
# find root StateChart
var root = get_parent()
while is_instance_valid(root) and not root is _StateChart:
root = root.get_parent()
if not is_instance_valid(root):
push_error("could not find root StateChart, cannot evaluate expression")
return false
# combine monitored states with expression properties
var properties: Dictionary = root._expression_properties.duplicate()
for node in checked_states:
var state = get_node_or_null(node)
if is_instance_valid(state) and state is _State:
properties["in_" + state.name] = state.active
# construct expression and set up properties
var expression := Expression.new()
var input_names = properties.keys()
# attempt to parse expression
var parse_result = expression.parse(guard_expression, input_names)
if parse_result != OK:
push_error("error parsing expression: " + expression.get_error_text())
return false
# create array of input values
var input_values = []
for input_name in input_names:
input_values.append(properties[input_name])
# execute expression and validate result
var result = expression.execute(input_values)
if expression.has_execute_failed():
push_error("failed to execute expression: " + expression.get_error_text())
return false
if typeof(result) != TYPE_BOOL:
push_error("result is not a boolean value. returning false")
return false
return result

View file

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<rect id="Artboard1" x="0" y="0" width="32" height="32" style="fill:none;"/>
<g id="Artboard11" serif:id="Artboard1">
<g transform="matrix(1.03705,0,0,1.03705,-0.460588,-0.659827)">
<g id="BG">
<path d="M30.337,8.833C30.337,4.841 27.096,1.601 23.104,1.601L8.64,1.601C4.649,1.601 1.408,4.841 1.408,8.833L1.408,23.297C1.408,27.288 4.649,30.529 8.64,30.529L23.104,30.529C27.096,30.529 30.337,27.288 30.337,23.297L30.337,8.833Z" style="fill:none;stroke:rgb(225,142,57);stroke-width:0.96px;"/>
</g>
</g>
<g id="Transition">
<g transform="matrix(0.59386,-0.00129228,-0.00129228,0.999996,1.73018,-0.223543)">
<path d="M14.852,23.427C30.642,25.277 38.781,18.528 34.54,10.944" style="fill:none;stroke:rgb(225,142,57);stroke-width:2.44px;"/>
</g>
<g transform="matrix(1.36246,0,0,1.36246,-3.81851,-16.9755)">
<circle cx="19.207" cy="19.263" r="4.404" style="fill:rgb(225,142,57);"/>
</g>
<g transform="matrix(1.36246,0,0,1.36246,-16.9151,-2.76732)">
<circle cx="19.207" cy="19.263" r="4.404" style="fill:rgb(225,142,57);"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,35 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/transition.svg-20a1a52a85a71c731b2386952d47b2f7.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/godot_state_charts/transition.svg"
dest_files=[ "res://.import/transition.svg-20a1a52a85a71c731b2386952d47b2f7.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=false
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
process/normal_map_invert_y=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View file

@ -9,13 +9,49 @@
config_version=4
_global_script_classes=[ {
"base": "State",
"class": "AtomicState",
"language": "GDScript",
"path": "res://addons/godot_state_charts/atomic_state.gd"
}, {
"base": "State",
"class": "CompoundState",
"language": "GDScript",
"path": "res://addons/godot_state_charts/compound_state.gd"
}, {
"base": "Resource",
"class": "LevelEntry",
"language": "GDScript",
"path": "res://scripts/level_entry.gd"
}, {
"base": "State",
"class": "ParallelState",
"language": "GDScript",
"path": "res://addons/godot_state_charts/parallel_state.gd"
}, {
"base": "Node",
"class": "State",
"language": "GDScript",
"path": "res://addons/godot_state_charts/state.gd"
}, {
"base": "Node",
"class": "StateChart",
"language": "GDScript",
"path": "res://addons/godot_state_charts/state_chart.gd"
}, {
"base": "Node",
"class": "Transition",
"language": "GDScript",
"path": "res://addons/godot_state_charts/transition.gd"
} ]
_global_script_class_icons={
"LevelEntry": ""
"AtomicState": "res://addons/godot_state_charts/atomic_state.svg",
"CompoundState": "res://addons/godot_state_charts/compound_state.svg",
"LevelEntry": "",
"ParallelState": "res://addons/godot_state_charts/parallel_state.svg",
"State": "",
"StateChart": "res://addons/godot_state_charts/state_chart.svg",
"Transition": "res://addons/godot_state_charts/transition.svg"
}
[application]
@ -49,7 +85,7 @@ window/handheld/orientation="sensor_landscape"
[editor_plugins]
enabled=PoolStringArray( )
enabled=PoolStringArray( "res://addons/godot_state_charts/plugin.cfg" )
[global]