From 1ac04f54e01320190aa45e44224cb6702dd472ef Mon Sep 17 00:00:00 2001 From: frcroth Date: Fri, 2 Feb 2024 15:17:50 +0100 Subject: [PATCH 1/3] Improve state machine behavior documentation --- .../pronto/behaviors/StateMachineBehavior.gd | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/addons/pronto/behaviors/StateMachineBehavior.gd b/addons/pronto/behaviors/StateMachineBehavior.gd index 46bbf2f5..fe0527f4 100644 --- a/addons/pronto/behaviors/StateMachineBehavior.gd +++ b/addons/pronto/behaviors/StateMachineBehavior.gd @@ -3,24 +3,26 @@ extends Behavior class_name StateMachineBehavior -## The StateMachineBehavior is a [class Behavior] that acts as a purely graphic -## hint as to which [class StateBehavior] objects belong to the same state machine. -## The [class GroupDrawer] is used for this. +## The StateMachineBehavior is a [class Behavior] that is a part of a state +## state machine. Fill the state machine with states by creating +## [class StateBehavior] nodes as children. +## The StateMachineBehavior manages the active state and can receive triggers +## from outside, which are then available on the active state. ## Signal that gets emitted when the trigger method is called on this state machine. signal triggered(trigger: String) var active_state: StateBehavior = null -## Name of the trigger that is called in every frame. -const always_trigger = "always" - ## List of the triggers that this state machine processes. Triggers are used in ## trigger method and the "on_trigger_received" method of [class StateBehavior]. -## Both these ways use the [class StateTransitionConfigurator], which allows the creation -## of triggers. +## Both these ways use the [class StateTransitionConfigurator], which allows the +## creation of triggers. @export var triggers: Array[String] = [always_trigger] +## Name of the trigger that is called in every frame. +const always_trigger = "always" + ## When true, the state machine will trigger the "always" trigger on every frame, ## allowing state transitions without other triggers. @export var trigger_always: bool = true From b7c69fde530b9c08cc9078b06f3060455c1ddfc9 Mon Sep 17 00:00:00 2001 From: frcroth Date: Fri, 2 Feb 2024 15:27:09 +0100 Subject: [PATCH 2/3] Always color always trigger in trigger list --- addons/pronto/helpers/StateMachineInfo.gd | 53 +++++++++++++++++++---- 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/addons/pronto/helpers/StateMachineInfo.gd b/addons/pronto/helpers/StateMachineInfo.gd index 7efa8a1e..a44e03ce 100644 --- a/addons/pronto/helpers/StateMachineInfo.gd +++ b/addons/pronto/helpers/StateMachineInfo.gd @@ -8,17 +8,22 @@ var processing_trigger = false @export var onlyInEditor: bool = true + # Called when the node enters the scene tree for the first time. func _ready(): redraw_periodically() + func redraw_periodically(): while is_inside_tree(): await get_tree().create_timer(1).timeout if not processing_trigger: queue_redraw() + var active_trigger = "" + + func _redraw_with_trigger(trigger): if trigger != StateMachineBehavior.always_trigger: active_trigger = trigger @@ -29,33 +34,63 @@ func _redraw_with_trigger(trigger): queue_redraw() processing_trigger = false + # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): pass + var label_position = Vector2.ZERO + func get_label_position(): var states = get_parent().get_children() - if states.size() == 0: return Vector2(150,0) + if states.size() == 0: + return Vector2(150, 0) var max_x = 0 for node in states: - max_x = max(node.position.x/2, max_x) + max_x = max(node.position.x / 2, max_x) return Vector2(max_x + 150, 0) + +func _draw_trigger_as_active(trigger): + if trigger == active_trigger: + return true + if trigger == get_parent().always_trigger && get_parent().trigger_always: + return true + return false + + func _draw(): - if not get_parent() is StateMachineBehavior: return + if not get_parent() is StateMachineBehavior: + return var state_machine: StateMachineBehavior = get_parent() var font_size = 10 - var label = "Triggers:" - var label_size = ThemeDB.fallback_font.get_string_size(label, HORIZONTAL_ALIGNMENT_CENTER, -1, font_size) + var label_size = ThemeDB.fallback_font.get_string_size( + label, HORIZONTAL_ALIGNMENT_CENTER, -1, font_size + ) label_position = get_label_position() - draw_string(ThemeDB.fallback_font, label_position, label, HORIZONTAL_ALIGNMENT_CENTER, -1, font_size, color) + draw_string( + ThemeDB.fallback_font, + label_position, + label, + HORIZONTAL_ALIGNMENT_CENTER, + -1, + font_size, + color + ) for trigger in state_machine.triggers: label = trigger label_position.y += label_size.y - var label_color = triggered_color if trigger == active_trigger else color - draw_string(ThemeDB.fallback_font, label_position, label, HORIZONTAL_ALIGNMENT_CENTER, -1, font_size, label_color) - + var label_color = triggered_color if _draw_trigger_as_active(trigger) else color + draw_string( + ThemeDB.fallback_font, + label_position, + label, + HORIZONTAL_ALIGNMENT_CENTER, + -1, + font_size, + label_color + ) From b7d43e105ee9e3125155682066c066abde914454 Mon Sep 17 00:00:00 2001 From: frcroth Date: Sat, 3 Feb 2024 18:03:45 +0100 Subject: [PATCH 3/3] Add unsaved marker for state transition configurator --- .../state_transition_configurator.gd | 16 ++++++++++++++-- .../state_transition_configurator.tscn | 4 +++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/addons/pronto/signal_connecting/state_transition_configurator.gd b/addons/pronto/signal_connecting/state_transition_configurator.gd index ec46a1d5..da3c458c 100644 --- a/addons/pronto/signal_connecting/state_transition_configurator.gd +++ b/addons/pronto/signal_connecting/state_transition_configurator.gd @@ -107,6 +107,9 @@ func redraw_receiver_label(): else: %ReceiverLabel.text = "Connecting to state ${0} ({1})".format([from.get_path_to(receiver), receiver.name]) +func _get_trigger_for_connection(connection: Connection): + return connection.trigger if connection.is_state_transition() else extract_trigger_from_trigger_argument_script(connection.arguments[0]) + func set_existing_connection(from: Node, connection: Connection): self.from = from existing_connection = connection @@ -129,7 +132,7 @@ func set_existing_connection(from: Node, connection: Connection): #%SharedLinksNote.visible = total["total"] > 1 #%SharedLinksCount.text = "This connection is linked to {0} other node{1}.".format([total["total"] - 1, "s" if total["total"] != 2 else ""]) reload_triggers() - var selected_trigger = connection.trigger if connection.is_state_transition() else extract_trigger_from_trigger_argument_script(connection.arguments[0]) + var selected_trigger = _get_trigger_for_connection(connection) for i in range(%TriggerSelection.item_count): if %TriggerSelection.get_item_text(i) == selected_trigger: %TriggerSelection.select(i) @@ -188,9 +191,12 @@ func argument_names(): func argument_types(): return argument_names_and_types().map(func (a): return a[1]) + +func _get_selected_trigger(): + return %TriggerSelection.get_item_text(%TriggerSelection.get_selected_id()) func save(): - var trigger = %TriggerSelection.get_item_text(%TriggerSelection.get_selected_id()) + var trigger = _get_selected_trigger() if existing_connection: Utils.commit_undoable(undo_redo, "Update condition of connection", existing_connection.only_if, {"source_code": %Condition.text}, "reload") @@ -345,6 +351,12 @@ func _on_add_trigger_pressed(): %TriggerSelection.add_item(new_trigger) %TriggerSelection.select(len(get_state_machine().triggers)-1) %TriggerEdit.text = "" + +func _on_trigger_selection_item_selected(index): + mark_changed(true) + +func _on_condition_text_changed(): + mark_changed(true) func _on_done_pressed(): save() diff --git a/addons/pronto/signal_connecting/state_transition_configurator.tscn b/addons/pronto/signal_connecting/state_transition_configurator.tscn index 2b1de289..a0e87ce9 100644 --- a/addons/pronto/signal_connecting/state_transition_configurator.tscn +++ b/addons/pronto/signal_connecting/state_transition_configurator.tscn @@ -174,7 +174,7 @@ sync_handles_x = true [node name="Condition" parent="MarginContainer/VBoxContainer/HBoxContainer2/ResizableContainer2" instance=ExtResource("3_immw5")] unique_name_in_owner = true -custom_minimum_size = Vector2(0, 43.9353) +custom_minimum_size = Vector2(0, 43.3363) layout_mode = 2 default_text = "true" max_width = 500 @@ -205,7 +205,9 @@ layout_mode = 2 [connection signal="gui_input" from="." to="." method="_on_gui_input"] [connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer/AddReferenceButton" to="." method="_on_add_reference_button_pressed"] [connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer/remove" to="." method="_on_remove_pressed"] +[connection signal="item_selected" from="MarginContainer/VBoxContainer/TriggerContainer/HBoxContainer/TriggerSelection" to="." method="_on_trigger_selection_item_selected"] [connection signal="pressed" from="MarginContainer/VBoxContainer/TriggerContainer/TriggerCreationContainer/create_trigger" to="." method="_on_add_trigger_pressed"] +[connection signal="text_changed" from="MarginContainer/VBoxContainer/HBoxContainer2/ResizableContainer2/Condition" to="." method="_on_condition_text_changed"] [connection signal="pressed" from="MarginContainer/VBoxContainer/ButtonList/done" to="." method="_on_done_pressed"] [connection signal="pressed" from="MarginContainer/VBoxContainer/ButtonList/cancel" to="." method="_on_cancel_pressed"] [connection signal="pressed" from="MarginContainer/VBoxContainer/ButtonList/open_in_connection_editor" to="." method="_on_open_in_connection_editor_pressed"]