Added graphedit node highlighting and scrolling
parent
fcbd269f68
commit
b187b96507
|
@ -216,8 +216,8 @@ size_flags_vertical = 8
|
||||||
|
|
||||||
[node name="TreeVisualizer" type="Window" parent="Camera2D/CanvasLayer"]
|
[node name="TreeVisualizer" type="Window" parent="Camera2D/CanvasLayer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
position = Vector2i(0, 36)
|
position = Vector2i(520, 41)
|
||||||
size = Vector2i(1075, 225)
|
size = Vector2i(615, 595)
|
||||||
script = ExtResource("5_ecfvx")
|
script = ExtResource("5_ecfvx")
|
||||||
|
|
||||||
[node name="GraphEdit" type="GraphEdit" parent="Camera2D/CanvasLayer/TreeVisualizer"]
|
[node name="GraphEdit" type="GraphEdit" parent="Camera2D/CanvasLayer/TreeVisualizer"]
|
||||||
|
@ -229,6 +229,7 @@ grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
size_flags_vertical = 3
|
size_flags_vertical = 3
|
||||||
|
scroll_offset = Vector2(-77, -25)
|
||||||
show_menu = false
|
show_menu = false
|
||||||
show_zoom_buttons = false
|
show_zoom_buttons = false
|
||||||
show_grid_buttons = false
|
show_grid_buttons = false
|
||||||
|
|
|
@ -93,6 +93,8 @@ func _on_game_tick_timeout() -> void:
|
||||||
|
|
||||||
player.game_tick()
|
player.game_tick()
|
||||||
|
|
||||||
|
tree_visualizer.update_task_statuses(player.behavior_tree.blackboard)
|
||||||
|
|
||||||
tilemap_navigation.game_tick_end()
|
tilemap_navigation.game_tick_end()
|
||||||
world.game_tick_end()
|
world.game_tick_end()
|
||||||
EventsTracker.populate_visual_log(%RecentEventsLog, self)
|
EventsTracker.populate_visual_log(%RecentEventsLog, self)
|
||||||
|
|
|
@ -70,15 +70,7 @@ func get_first_child() -> Task:
|
||||||
|
|
||||||
|
|
||||||
func human_readable(addon: String = "") -> String:
|
func human_readable(addon: String = "") -> String:
|
||||||
var clear_status: String = "UNKNOWN"
|
var clear_status: String = clear_status()
|
||||||
if status == FAILURE:
|
|
||||||
clear_status = "FAILURE"
|
|
||||||
elif status == SUCCESS:
|
|
||||||
clear_status = "SUCCESS"
|
|
||||||
elif status == RUNNING:
|
|
||||||
clear_status = "RUNNING"
|
|
||||||
elif status == SUCCESS_STOP:
|
|
||||||
clear_status = "SUCCESS_STOP"
|
|
||||||
|
|
||||||
var ret: String = name;
|
var ret: String = name;
|
||||||
if addon != "":
|
if addon != "":
|
||||||
|
@ -91,6 +83,18 @@ func human_readable(addon: String = "") -> String:
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
func clear_status() -> String:
|
||||||
|
if status == FAILURE:
|
||||||
|
return "FAILURE"
|
||||||
|
elif status == SUCCESS:
|
||||||
|
return "SUCCESS"
|
||||||
|
elif status == RUNNING:
|
||||||
|
return "RUNNING"
|
||||||
|
elif status == SUCCESS_STOP:
|
||||||
|
return "SUCCESS_STOP"
|
||||||
|
return "UNKNOWN"
|
||||||
|
|
||||||
|
|
||||||
# SECTION: utility
|
# SECTION: utility
|
||||||
|
|
||||||
func find_closest_item(blackboard: Dictionary, item_types: Array[Vector2i], memory_key: String, max_distance: int = -1) -> Dictionary:
|
func find_closest_item(blackboard: Dictionary, item_types: Array[Vector2i], memory_key: String, max_distance: int = -1) -> Dictionary:
|
||||||
|
|
|
@ -13,11 +13,11 @@ func run(blackboard: Dictionary) -> void:
|
||||||
if c.status == SUCCESS_STOP:
|
if c.status == SUCCESS_STOP:
|
||||||
c.status = SUCCESS
|
c.status = SUCCESS
|
||||||
status = SUCCESS
|
status = SUCCESS
|
||||||
status_reason = "stopping at child " + c.name + ", as it returned SUCCESS_STOP"
|
status_reason = "stopping at " + c.name + " (STOP)"
|
||||||
return
|
return
|
||||||
if c.status != FAILURE:
|
if c.status != FAILURE:
|
||||||
status = c.status
|
status = c.status
|
||||||
status_reason = "stopped at child " + c.name
|
status_reason = "stopped at " + c.name
|
||||||
return
|
return
|
||||||
status = FAILURE
|
status = FAILURE
|
||||||
status_reason = "all children failed"
|
status_reason = "all children failed"
|
||||||
|
|
|
@ -13,11 +13,11 @@ func run(blackboard: Dictionary) -> void:
|
||||||
if c.status == SUCCESS_STOP:
|
if c.status == SUCCESS_STOP:
|
||||||
c.status = SUCCESS
|
c.status = SUCCESS
|
||||||
status = SUCCESS
|
status = SUCCESS
|
||||||
status_reason = "stopping at child " + c.name + ", as it returned SUCCESS_STOP"
|
status_reason = "stopping at " + c.name + " (STOP)"
|
||||||
return
|
return
|
||||||
if c.status != SUCCESS:
|
if c.status != SUCCESS:
|
||||||
status = c.status
|
status = c.status
|
||||||
status_reason = "stopped at child " + c.name
|
status_reason = "stopped at " + c.name
|
||||||
return
|
return
|
||||||
status = SUCCESS
|
status = SUCCESS
|
||||||
status_reason = "all children succeeded"
|
status_reason = "all children succeeded"
|
||||||
|
|
|
@ -7,10 +7,13 @@ const D_TREE_NODE: PackedScene = preload("res://scripts/visualization/d_tree_nod
|
||||||
#
|
#
|
||||||
var behavior_tree: BehaviorTree
|
var behavior_tree: BehaviorTree
|
||||||
#
|
#
|
||||||
var x_spacing: int = 400
|
var x_spacing: int = 430
|
||||||
var y_spacing: int = 100
|
var y_spacing: int = 100
|
||||||
#
|
#
|
||||||
var all_nodes: Array[DTreeNode] = []
|
var all_nodes: Array[DTreeNode] = []
|
||||||
|
# Dictionary[Task, DTreeNode]
|
||||||
|
var task_to_node: Dictionary = {}
|
||||||
|
var parent_nodes: Dictionary = {}
|
||||||
#
|
#
|
||||||
var current_lowest_node_pos: Vector2 = Vector2(0, 0)
|
var current_lowest_node_pos: Vector2 = Vector2(0, 0)
|
||||||
|
|
||||||
|
@ -46,13 +49,15 @@ func build_tree_from_task(task: Task, depth: int) -> DTreeNode:
|
||||||
|
|
||||||
var current_node: DTreeNode = D_TREE_NODE.instantiate()
|
var current_node: DTreeNode = D_TREE_NODE.instantiate()
|
||||||
graph_edit.add_child(current_node)
|
graph_edit.add_child(current_node)
|
||||||
|
task_to_node[task] = current_node
|
||||||
current_node.name = task.get_name() + str(randf())
|
current_node.name = task.get_name() + str(randf())
|
||||||
current_node.title = transform_string(task.get_name())
|
current_node.title = human_readable_task_name(task.get_name())
|
||||||
current_node.add_label("status", true, true)
|
current_node.add_label("status", true, true)
|
||||||
all_nodes.append(current_node)
|
all_nodes.append(current_node)
|
||||||
|
|
||||||
for child in child_nodes:
|
for child in child_nodes:
|
||||||
graph_edit.connect_node(current_node.name, 0, child.name, 0)
|
graph_edit.connect_node(current_node.name, 0, child.name, 0)
|
||||||
|
parent_nodes[child] = current_node
|
||||||
|
|
||||||
if child_node_positions.size() > 0:
|
if child_node_positions.size() > 0:
|
||||||
var average_position: Vector2 = Vector2(0, 0)
|
var average_position: Vector2 = Vector2(0, 0)
|
||||||
|
@ -72,7 +77,43 @@ func build_tree_from_task(task: Task, depth: int) -> DTreeNode:
|
||||||
|
|
||||||
return current_node
|
return current_node
|
||||||
|
|
||||||
func transform_string(input: String) -> String:
|
|
||||||
|
func update_task_statuses(blackboard: Dictionary) -> void:
|
||||||
|
for t in task_to_node.keys():
|
||||||
|
var task: Task = t as Task
|
||||||
|
var node: DTreeNode = task_to_node[task]
|
||||||
|
var status: int = task.status
|
||||||
|
var clear_status: String = task.clear_status()
|
||||||
|
var status_reason: String = task.status_reason
|
||||||
|
|
||||||
|
if status_reason != "":
|
||||||
|
node.set_label_text(0, status_reason)
|
||||||
|
else:
|
||||||
|
node.set_label_text(0, clear_status)
|
||||||
|
|
||||||
|
node.set_body_color(node.color_normal)
|
||||||
|
if status == Task.RUNNING or status == Task.SUCCESS or status == Task.SUCCESS_STOP:
|
||||||
|
node.set_body_color(node.color_success)
|
||||||
|
|
||||||
|
if blackboard.has("current_task"):
|
||||||
|
var selected_node = task_to_node[blackboard["current_task"]]
|
||||||
|
if selected_node:
|
||||||
|
center_view_on_position(selected_node.position_offset)
|
||||||
|
selected_node.set_body_color(selected_node.color_executed)
|
||||||
|
while parent_nodes.has(selected_node):
|
||||||
|
selected_node = parent_nodes[selected_node]
|
||||||
|
selected_node.set_body_color(selected_node.color_checked)
|
||||||
|
|
||||||
|
|
||||||
|
func center_view_on_position(target_position: Vector2) -> void:
|
||||||
|
var graph_edit_size: Vector2 = graph_edit.size
|
||||||
|
var zoom: float = graph_edit.zoom
|
||||||
|
var offset_x: float = target_position.x * zoom - graph_edit_size.x / 2
|
||||||
|
var offset_y: float = target_position.y * zoom - graph_edit_size.y / 2
|
||||||
|
graph_edit.scroll_offset = Vector2(offset_x, offset_y)
|
||||||
|
|
||||||
|
|
||||||
|
func human_readable_task_name(input: String) -> String:
|
||||||
var prefixes: Dictionary = {"sl_": "Selector: ", "sq_": "Sequence: ", "Task": ""}
|
var prefixes: Dictionary = {"sl_": "Selector: ", "sq_": "Sequence: ", "Task": ""}
|
||||||
var selected_prefix: String = ""
|
var selected_prefix: String = ""
|
||||||
|
|
||||||
|
@ -86,7 +127,7 @@ func transform_string(input: String) -> String:
|
||||||
var current_word: String = ""
|
var current_word: String = ""
|
||||||
|
|
||||||
for i in range(input.length()):
|
for i in range(input.length()):
|
||||||
var character = input[i]
|
var character: String = input[i]
|
||||||
if character.to_upper() == character and current_word.length() > 0:
|
if character.to_upper() == character and current_word.length() > 0:
|
||||||
words.append(current_word)
|
words.append(current_word)
|
||||||
current_word = "" + character.to_lower()
|
current_word = "" + character.to_lower()
|
||||||
|
|
|
@ -3,13 +3,17 @@ extends GraphNode
|
||||||
|
|
||||||
var left_slots: Array[String] = []
|
var left_slots: Array[String] = []
|
||||||
var right_slots: Array[String] = []
|
var right_slots: Array[String] = []
|
||||||
var color_highlighted: StyleBoxFlat = StyleBoxFlat.new()
|
|
||||||
var color_normal: StyleBoxFlat = StyleBoxFlat.new()
|
var color_normal: StyleBoxFlat = StyleBoxFlat.new()
|
||||||
|
var color_success: StyleBoxFlat = StyleBoxFlat.new()
|
||||||
|
var color_executed: StyleBoxFlat = StyleBoxFlat.new()
|
||||||
|
var color_checked: StyleBoxFlat = StyleBoxFlat.new()
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
color_highlighted.bg_color = Color(0.67058825, 1.0, 0.5411765)
|
|
||||||
color_normal.bg_color = Color(1.0, 1.0, 1.0)
|
color_normal.bg_color = Color(1.0, 1.0, 1.0)
|
||||||
|
color_success.bg_color = Color(0.25490198, 0.78431374, 0.9529412)
|
||||||
|
color_executed.bg_color = Color(0.5058824, 0.9529412, 0.30588236)
|
||||||
|
color_checked.bg_color = Color(0.6509804, 0.9254902, 0.5372549)
|
||||||
|
|
||||||
|
|
||||||
func add_label(label_text: String, left: bool, right: bool) -> Vector3i:
|
func add_label(label_text: String, left: bool, right: bool) -> Vector3i:
|
||||||
|
@ -33,8 +37,9 @@ func add_label(label_text: String, left: bool, right: bool) -> Vector3i:
|
||||||
return Vector3i(child_index, left_slots.size() - 1, right_slots.size() - 1)
|
return Vector3i(child_index, left_slots.size() - 1, right_slots.size() - 1)
|
||||||
|
|
||||||
|
|
||||||
func set_highlighted(highlight: bool) -> void:
|
func set_body_color(color: StyleBoxFlat) -> void:
|
||||||
if highlight:
|
self.add_theme_stylebox_override("panel", color)
|
||||||
self.add_theme_stylebox_override("panel", color_highlighted)
|
|
||||||
else:
|
func set_label_text(label_index: int, text: String) -> void:
|
||||||
self.add_theme_stylebox_override("panel", color_normal)
|
var label: Label = self.get_child(label_index) as Label
|
||||||
|
label.text = text
|
||||||
|
|
Loading…
Reference in New Issue