diff --git a/blendalot_animation_node.cpp b/blendalot_animation_node.cpp index 4399e0f..f3751c0 100644 --- a/blendalot_animation_node.cpp +++ b/blendalot_animation_node.cpp @@ -5,9 +5,9 @@ #include "blendalot_animation_node.h" void BLTAnimationNode::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_graph_offset", "offset"), &BLTAnimationNode::set_graph_offset); - ClassDB::bind_method(D_METHOD("get_graph_offset"), &BLTAnimationNode::get_graph_offset); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset"); + ClassDB::bind_method(D_METHOD("set_position", "position"), &BLTAnimationNode::set_position); + ClassDB::bind_method(D_METHOD("get_position"), &BLTAnimationNode::get_position); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_position", "get_position"); ADD_SIGNAL(MethodInfo("animation_node_renamed", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name"))); ADD_SIGNAL(MethodInfo("animation_node_removed", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "name"))); @@ -60,6 +60,11 @@ void BLTAnimationNodeBlendTree::_bind_methods() { ClassDB::bind_method(D_METHOD("add_connection", "source_node", "target_node", "target_port_name"), &BLTAnimationNodeBlendTree::add_connection); ClassDB::bind_method(D_METHOD("remove_connection", "source_node", "target_node", "target_port_name"), &BLTAnimationNodeBlendTree::remove_connection); ClassDB::bind_method(D_METHOD("get_connections"), &BLTAnimationNodeBlendTree::get_connections_as_array); + + ClassDB::bind_method(D_METHOD("set_graph_offset", "graph_offset"), &BLTAnimationNodeBlendTree::set_graph_offset); + ClassDB::bind_method(D_METHOD("get_graph_offset"), &BLTAnimationNodeBlendTree::get_graph_offset); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_graph_offset", "get_graph_offset"); + BIND_CONSTANT(CONNECTION_OK); BIND_CONSTANT(CONNECTION_ERROR_GRAPH_ALREADY_INITIALIZED); BIND_CONSTANT(CONNECTION_ERROR_NO_SOURCE_NODE); @@ -98,7 +103,7 @@ bool BLTAnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_value) if (what == "graph_offset") { if (node_index != -1) { - r_value = tree_graph.nodes[node_index]->graph_offset; + r_value = tree_graph.nodes[node_index]->position; return true; } } @@ -139,7 +144,7 @@ bool BLTAnimationNodeBlendTree::_set(const StringName &p_name, const Variant &p_ if (what == "graph_offset") { int node_index = find_node_index_by_name(node_name); if (node_index > -1) { - tree_graph.nodes[node_index]->graph_offset = p_value; + tree_graph.nodes[node_index]->position = p_value; } return true; } diff --git a/blendalot_animation_node.h b/blendalot_animation_node.h index 0263bcb..f7a6ef3 100644 --- a/blendalot_animation_node.h +++ b/blendalot_animation_node.h @@ -257,13 +257,14 @@ public: double sync_position = 0.0; bool is_synced = false; - Animation::LoopMode loop_mode = Animation::LOOP_NONE; + // TODO: 2026-02-17: how to initialize loop_mode e.g. for a BlendTree or a StateMachine? + Animation::LoopMode loop_mode = Animation::LOOP_LINEAR; SyncTrack sync_track; }; NodeTimeInfo node_time_info; bool active = false; - Vector2 graph_offset; + Vector2 position; virtual ~BLTAnimationNode() override = default; virtual bool initialize(GraphEvaluationContext &context) { @@ -307,12 +308,12 @@ public: } } - void set_graph_offset(const Vector2 &p_position) { - graph_offset = p_position; + void set_position(const Vector2 &p_position) { + position = p_position; } - Vector2 get_graph_offset() const { - return graph_offset; + Vector2 get_position() const { + return position; } virtual Vector get_input_names() const { return {}; } @@ -597,6 +598,8 @@ protected: bool _set(const StringName &p_name, const Variant &p_value); public: + Vector2 graph_offset; + struct NodeRuntimeData { Vector> input_nodes; LocalVector input_data; @@ -604,6 +607,14 @@ public: }; LocalVector _node_runtime_data; + void set_graph_offset(const Vector2 &p_graph_offset) { + graph_offset = p_graph_offset; + } + + Vector2 get_graph_offset() const { + return graph_offset; + } + int find_node_index(const Ref &node) const { return tree_graph.find_node_index(node); } @@ -701,6 +712,8 @@ public: // overrides from BLTAnimationNode bool initialize(GraphEvaluationContext &context) override { + tree_initialized = false; + if (!BLTAnimationNode::initialize(context)) { return false; } @@ -716,6 +729,15 @@ public: } } + // All inputs must have a connected node. + for (const NodeRuntimeData &node_runtime_data : _node_runtime_data) { + for (const Ref &input_node : node_runtime_data.input_nodes) { + if (!input_node.is_valid()) { + return false; + } + } + } + tree_initialized = true; return true; diff --git a/demo/addons/blendalot/animation_graph_editor.gd b/demo/addons/blendalot/animation_graph_editor.gd new file mode 100644 index 0000000..fdef1f6 --- /dev/null +++ b/demo/addons/blendalot/animation_graph_editor.gd @@ -0,0 +1,105 @@ +@tool + +extends Control +class_name AnimationGraphEditor + +@onready var breadcrumb_button_container: HBoxContainer = %BreadcrumbButtons +@onready var active_graph_control: Control = %ActiveGraphControl + +var active_animation_graph_node:BLTAnimationGraph = null +var animation_graph_root_node:BLTAnimationNode = null +var graph_node_stack:Array[BLTAnimationNode] = [] +var active_graph_edit:Control = null +var active_graph_edit_index = -1 + +func reset_graph_control(): + for child in active_graph_control.get_children(): + active_graph_control.remove_child(child) + child.queue_free() + + +func edit_animation_root_node(blt_node:BLTAnimationNode): + graph_node_stack = [] + active_graph_edit_index = -1 + truncate_graph_stack(0) + + blt_node.resource_name = "Root" + + if blt_node is BLTAnimationNodeBlendTree: + animation_graph_root_node = blt_node + push_graph_stack(blt_node) + edit_graph(blt_node) + + push_warning("Cannot edit node %s. Graph type %s not yet supported." % [blt_node.resource_name, blt_node.get_class()]) + + +func push_graph_stack(blt_node:BLTAnimationNode): + graph_node_stack.append(blt_node) + active_graph_edit_index = graph_node_stack.size() - 1 + + var breadcrumb_button:Button = Button.new() + breadcrumb_button_container.add_child(breadcrumb_button) + breadcrumb_button.text = blt_node.resource_name + breadcrumb_button.toggle_mode = true + breadcrumb_button.set_meta("BLTAnimationNode", blt_node) + breadcrumb_button.set_meta("graph_edit_index", active_graph_edit_index) + breadcrumb_button.pressed.connect(on_breadcrumb_button_pressed.bind(active_graph_edit_index)) + + +func truncate_graph_stack(level:int): + graph_node_stack.resize(level) + + var is_above_stack_size = false + for child in breadcrumb_button_container.get_children(): + if is_above_stack_size: + breadcrumb_button_container.remove_child(child) + child.queue_free() + continue + + var button:Button = child as Button + if not is_instance_valid(button): + continue + + if button.get_meta("graph_edit_index") >= graph_node_stack.size(): + is_above_stack_size = true + breadcrumb_button_container.remove_child(child) + child.queue_free() + + +func on_breadcrumb_button_pressed(graph_edit_index:int): + print("on_breadcrumb_button_pressed(%d)" % graph_edit_index) + active_graph_edit_index = graph_edit_index + update_breadcrumb_button_container() + + edit_graph(graph_node_stack[graph_edit_index]) + + +func update_breadcrumb_button_container(): + for child in breadcrumb_button_container.get_children(): + var button:Button = child as Button + if not is_instance_valid(button): + continue + + if button.get_meta("graph_edit_index") == active_graph_edit_index: + button.set_pressed_no_signal(true) + else: + button.set_pressed_no_signal(false) + + +func edit_graph(blt_node:BLTAnimationNode): + if blt_node is BLTAnimationNodeBlendTree: + reset_graph_control() + var blend_tree_graph_edit:BltBlendTreeEditor = preload ("res://addons/blendalot/blend_tree_editor.tscn").instantiate() + active_graph_control.add_child(blend_tree_graph_edit) + blend_tree_graph_edit.edit_blend_tree(blt_node) + blend_tree_graph_edit.edit_subgraph.connect(handle_subgraph_edit) + active_graph_edit = blend_tree_graph_edit + else: + push_error("Cannot edit graph of node type %s" % blt_node.get_class()) + + +func handle_subgraph_edit(blt_node:BLTAnimationNode): + print("handling subgraph edit of node %s" % blt_node.resource_name) + truncate_graph_stack(active_graph_edit_index + 1) + push_graph_stack(blt_node) + edit_graph(blt_node) diff --git a/demo/addons/blendalot/animation_graph_editor.gd.uid b/demo/addons/blendalot/animation_graph_editor.gd.uid new file mode 100644 index 0000000..027e630 --- /dev/null +++ b/demo/addons/blendalot/animation_graph_editor.gd.uid @@ -0,0 +1 @@ +uid://bxxipuj2s5gxu diff --git a/demo/addons/blendalot/animation_graph_editor.tscn b/demo/addons/blendalot/animation_graph_editor.tscn new file mode 100644 index 0000000..13ab95f --- /dev/null +++ b/demo/addons/blendalot/animation_graph_editor.tscn @@ -0,0 +1,83 @@ +[gd_scene format=3 uid="uid://bk5mssvanwjnh"] + +[ext_resource type="Script" uid="uid://bxxipuj2s5gxu" path="res://addons/blendalot/animation_graph_editor.gd" id="1_un1ur"] +[ext_resource type="PackedScene" uid="uid://cptd46rpm0gl3" path="res://addons/blendalot/blend_tree_editor.tscn" id="2_utax0"] + +[node name="AnimationGraphEditor" type="VBoxContainer" unique_id=768619585] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource("1_un1ur") + +[node name="DebugContainer" type="HBoxContainer" parent="." unique_id=1984631897] +visible = false +layout_mode = 2 + +[node name="ResetGraphButton" type="Button" parent="DebugContainer" unique_id=670074781] +layout_mode = 2 +size_flags_horizontal = 0 +text = "Reset" + +[node name="FileNameLineEdit" type="LineEdit" parent="DebugContainer" unique_id=724929522] +unique_name_in_owner = true +custom_minimum_size = Vector2(250, 0) +layout_mode = 2 +text = "editor_test_tree.tres" + +[node name="SaveButton" type="Button" parent="DebugContainer" unique_id=706843675] +layout_mode = 2 +size_flags_horizontal = 0 +text = "Save +" + +[node name="LoadButton" type="Button" parent="DebugContainer" unique_id=1467831200] +layout_mode = 2 +size_flags_horizontal = 0 +text = "Load +" + +[node name="ReinitializeButton" type="Button" parent="DebugContainer" unique_id=281924859] +layout_mode = 2 +size_flags_horizontal = 0 +text = "Reinitialize" + +[node name="TreeOptionButton" type="OptionButton" parent="DebugContainer" unique_id=2103827540] +unique_name_in_owner = true +layout_mode = 2 +selected = 0 +item_count = 2 +popup/item_0/text = "AnimationSampler" +popup/item_0/id = 1 +popup/item_1/text = "Blend2" +popup/item_1/id = 2 + +[node name="InstantiateTreeButton" type="Button" parent="DebugContainer" unique_id=735069321] +layout_mode = 2 +size_flags_horizontal = 0 +text = "Instantiate" + +[node name="NavigationBar" type="MarginContainer" parent="." unique_id=815609909] +layout_mode = 2 + +[node name="Panel" type="Panel" parent="NavigationBar" unique_id=996737763] +layout_mode = 2 + +[node name="BreadcrumbButtons" type="HBoxContainer" parent="NavigationBar" unique_id=1375619232] +unique_name_in_owner = true +layout_mode = 2 + +[node name="PathLabel" type="Label" parent="NavigationBar/BreadcrumbButtons" unique_id=1544570774] +layout_mode = 2 +text = "Path:" + +[node name="ActiveGraphControl" type="Control" parent="." unique_id=1769528277] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 + +[node name="BlendTreeEditor" parent="ActiveGraphControl" unique_id=1313738200 instance=ExtResource("2_utax0")] +layout_mode = 1 diff --git a/demo/addons/blendalot/blendalot_main_panel.gd b/demo/addons/blendalot/blend_tree_editor.gd similarity index 57% rename from demo/addons/blendalot/blendalot_main_panel.gd rename to demo/addons/blendalot/blend_tree_editor.gd index a82f38b..187762a 100644 --- a/demo/addons/blendalot/blendalot_main_panel.gd +++ b/demo/addons/blendalot/blend_tree_editor.gd @@ -1,19 +1,22 @@ @tool -class_name BlendalotMainPanel + extends Control +class_name BltBlendTreeEditor @onready var blend_tree_graph_edit: GraphEdit = %BlendTreeGraphEdit -@onready var file_name_line_edit: LineEdit = %FileNameLineEdit -@onready var tree_option_button: OptionButton = %TreeOptionButton @onready var add_node_popup_menu: PopupMenu = %AddNodePopupMenu -var root_animation_node:BLTAnimationNode = null -var last_edited_graph_node:GraphNode = null -var blend_tree:BLTAnimationNodeBlendTree = BLTAnimationNodeBlendTree.new() +signal edit_subgraph(blt_node:BLTAnimationNode) +signal graph_changed() + +var blend_tree:BLTAnimationNodeBlendTree + var blend_tree_node_to_graph_node = {} var graph_node_to_blend_tree_node = {} + var selected_nodes = {} -var new_node_position = Vector2.INF +var last_selected_graph_node:GraphNode = null +var new_node_position:Vector2 = Vector2.ZERO var registered_nodes = [ "BLTAnimationNodeSampler", @@ -21,7 +24,7 @@ var registered_nodes = [ "BLTAnimationNodeBlendTree", ] -# Called when the node enters the scene tree for the first time. + func _ready() -> void: add_node_popup_menu.clear(true) @@ -29,75 +32,6 @@ func _ready() -> void: add_node_popup_menu.add_item(node_name) -# Called every frame. 'delta' is the elapsed time since the previous frame. -func _process(delta: float) -> void: - pass - - -func create_node_for_blt_node(blt_node: BLTAnimationNode) -> GraphNode: - var result_graph_node:GraphNode = GraphNode.new() - result_graph_node.name = blt_node.resource_name - result_graph_node.title = blt_node.resource_name - result_graph_node.position_offset = blt_node.graph_offset - - var result_slot_offset = 0 - - if (blt_node.get_class() != "BLTAnimationNodeOutput"): - result_slot_offset = 1 - var output_slot_label:Label = Label.new() - output_slot_label.text = "Result" - result_graph_node.add_child(output_slot_label) - result_graph_node.set_slot(0, false, 1, Color.WHITE, true, 1, Color.WHITE) - - var inputs = blt_node.get_input_names() - for i in range(len(inputs)): - var slot_label:Label = Label.new() - slot_label.text = inputs[i] - result_graph_node.add_child(slot_label) - result_graph_node.set_slot(i + result_slot_offset, true, 1, Color.WHITE, false, 1, Color.BLACK) - - blt_node.node_changed.connect(_trigger_animation_graph_initialize) - - return result_graph_node - - -func _on_blend_tree_graph_edit_delete_nodes_request(nodes: Array[StringName]) -> void: - for node_name:StringName in nodes: - print("remove node '%s'" % node_name) - var blend_tree_node:BLTAnimationNode = blend_tree.get_node(node_name) - - if blend_tree_node == null: - push_error("Cannot delete node '%s': node not found." % node_name) - continue - - if blend_tree_node == blend_tree.get_output_node(): - push_warning("Output node not allowed to be removed.") - continue - - blend_tree_node.node_changed.disconnect(_trigger_animation_graph_initialize) - - var graph_node:GraphNode = blend_tree_node_to_graph_node[blend_tree_node] - blend_tree.remove_node(blend_tree_node) - blend_tree_node_to_graph_node.erase(blend_tree_node) - - _blend_tree_graph_edit_remove_node_connections(graph_node) - graph_node_to_blend_tree_node.erase(graph_node) - blend_tree_graph_edit.remove_child(graph_node) - _on_blend_tree_graph_edit_node_deselected(graph_node) - - EditorInterface.get_inspector().edit(null) - - -func _on_reset_graph_button_pressed() -> void: - EditorInterface.get_inspector().edit(null) - - _reset_editor() - _update_editor_from_blend_tree() - - var graph_rect:Rect2 = blend_tree_graph_edit.get_rect() - blend_tree_graph_edit.scroll_offset = graph_rect.size * -0.5 - Vector2(200,0) - - func _reset_editor(): for child in blend_tree_graph_edit.get_children(): if child.name == "_connection_layer": @@ -108,18 +42,16 @@ func _reset_editor(): blend_tree_graph_edit.clear_connections() - blend_tree = BLTAnimationNodeBlendTree.new() + blend_tree = null blend_tree_node_to_graph_node = {} graph_node_to_blend_tree_node = {} selected_nodes = {} + - -func edit_blend_tree(blend_tree_animation_node:BLTAnimationNode): - print("Starting to edit blend_tree_animation_node " + str(blend_tree_animation_node)) - print("Owner: %s" % blend_tree_animation_node) +func edit_blend_tree(blt_blend_tree:BLTAnimationNodeBlendTree): _reset_editor() - root_animation_node = blend_tree_animation_node - blend_tree = blend_tree_animation_node + blend_tree = blt_blend_tree + blend_tree_graph_edit.scroll_offset = blend_tree.graph_offset _update_editor_nodes_from_blend_tree() _update_editor_connections_from_blend_tree() @@ -128,7 +60,7 @@ func edit_blend_tree(blend_tree_animation_node:BLTAnimationNode): func _update_editor_nodes_from_blend_tree(): for node_name in blend_tree.get_node_names(): var blend_tree_node:BLTAnimationNode = blend_tree.get_node(node_name) - var graph_node:GraphNode = create_node_for_blt_node(blend_tree_node) + var graph_node:GraphNode = create_graph_node_for_blt_node(blend_tree_node) blend_tree_graph_edit.add_child(graph_node) blend_tree_node_to_graph_node[blend_tree_node] = graph_node @@ -148,60 +80,55 @@ func _update_editor_connections_from_blend_tree(): var connect_result = blend_tree_graph_edit.connect_node(source_node.resource_name, 0, target_node.resource_name, target_node.get_input_index(target_port), true) -func _update_editor_from_blend_tree(): - _update_editor_nodes_from_blend_tree() - _update_editor_connections_from_blend_tree() - - -func _on_save_button_pressed() -> void: - ResourceSaver.save(blend_tree, "res://" + file_name_line_edit.text) - - -func _on_load_button_pressed() -> void: - var loaded_blend_tree:BLTAnimationNodeBlendTree = ResourceLoader.load("res://" + file_name_line_edit.text, "BLTAnimationNodeBlendTree", 0) - - if loaded_blend_tree: - _reset_editor() - blend_tree = loaded_blend_tree - _update_editor_from_blend_tree() - - -func _on_instantiate_tree_button_pressed() -> void: - var graph_name = tree_option_button.get_item_text(tree_option_button.selected) +func create_graph_node_for_blt_node(blt_node: BLTAnimationNode) -> GraphNode: + var result_graph_node:GraphNode = GraphNode.new() + result_graph_node.name = blt_node.resource_name + result_graph_node.title = blt_node.resource_name + result_graph_node.position_offset = blt_node.position - if graph_name == "AnimationSampler": - _reset_editor() - - var sampler_node:BLTAnimationNodeSampler = BLTAnimationNodeSampler.new() - sampler_node.animation = "SampleLibrary/Idle" - - blend_tree.add_node(sampler_node) - blend_tree.add_connection(sampler_node, blend_tree.get_output_node(), "Output") - - _update_editor_from_blend_tree() - elif graph_name == "Blend2": - _reset_editor() - - var sampler_node_walk:BLTAnimationNodeSampler = BLTAnimationNodeSampler.new() - sampler_node_walk.animation = "SampleLibrary/Walk" - - var sampler_node_run:BLTAnimationNodeSampler = BLTAnimationNodeSampler.new() - sampler_node_run.animation = "SampleLibrary/Run" - - var blend2_node:BLTAnimationNodeBlend2 = BLTAnimationNodeBlend2.new() - - blend_tree.add_node(sampler_node_walk) - blend_tree.add_node(sampler_node_run) - blend_tree.add_node(blend2_node) - - blend_tree.add_connection(blend2_node, blend_tree.get_output_node(), "Output") - - blend_tree.add_connection(sampler_node_walk, blend2_node, "Input0") - blend_tree.add_connection(sampler_node_run, blend2_node, "Input1") - - _update_editor_from_blend_tree() + var result_slot_offset = 0 + + if (blt_node.get_class() != "BLTAnimationNodeOutput"): + result_slot_offset = 1 + var output_slot_label:Label = Label.new() + output_slot_label.text = "Result" + result_graph_node.add_child(output_slot_label) + result_graph_node.set_slot(0, false, 1, Color.WHITE, true, 1, Color.WHITE) + + if blt_node.get_class() == "BLTAnimationNodeBlendTree": + result_graph_node.gui_input.connect(_on_node_gui_input.bind(result_graph_node)) + + var inputs = blt_node.get_input_names() + for i in range(len(inputs)): + var slot_label:Label = Label.new() + slot_label.text = inputs[i] + result_graph_node.add_child(slot_label) + result_graph_node.set_slot(i + result_slot_offset, true, 1, Color.WHITE, false, 1, Color.BLACK) + + blt_node.node_changed.connect(_trigger_graph_changed) + + return result_graph_node +func _trigger_graph_changed(): + graph_changed.emit() + + +func _remove_node_connections(graph_node:GraphNode): + var node_connections:Array = [] + + for connection:Dictionary in blend_tree_graph_edit.connections: + if connection["from_node"] == graph_node.name or connection["to_node"] == graph_node.name: + node_connections.append(connection) + + for node_connection:Dictionary in node_connections: + print("Removing connection %s" % str(node_connection)) + blend_tree_graph_edit.disconnect_node(node_connection["from_node"], node_connection["from_port"], node_connection["to_node"], node_connection["to_port"]) + + +# +# GraphEdit signal handling +# func _on_blend_tree_graph_edit_connection_request(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> void: print("Trying to connect '%s' port %d to node '%s' port %d" % [from_node, from_port, to_node, to_port]) @@ -227,19 +154,36 @@ func _on_blend_tree_graph_edit_connection_request(from_node: StringName, from_po print("Success!") +func _on_blend_tree_graph_edit_delete_nodes_request(nodes: Array[StringName]) -> void: + for node_name:StringName in nodes: + print("remove node '%s'" % node_name) + var blend_tree_node:BLTAnimationNode = blend_tree.get_node(node_name) + + if blend_tree_node == null: + push_error("Cannot delete node '%s': node not found." % node_name) + continue + + if blend_tree_node == blend_tree.get_output_node(): + push_warning("Output node not allowed to be removed.") + continue + + blend_tree_node.node_changed.disconnect(_trigger_graph_changed) + + var graph_node:GraphNode = blend_tree_node_to_graph_node[blend_tree_node] + blend_tree.remove_node(blend_tree_node) + blend_tree_node_to_graph_node.erase(blend_tree_node) + + _remove_node_connections(graph_node) + graph_node_to_blend_tree_node.erase(graph_node) + blend_tree_graph_edit.remove_child(graph_node) + _on_blend_tree_graph_edit_node_deselected(graph_node) + + EditorInterface.get_inspector().edit(null) + + func _on_blend_tree_graph_edit_end_node_move() -> void: for graph_node:GraphNode in selected_nodes.keys(): - graph_node_to_blend_tree_node[graph_node].graph_offset = graph_node.position_offset - - -func _on_blend_tree_graph_edit_begin_node_move() -> void: - pass # Replace with function body. - - -func _on_blend_tree_graph_edit_node_selected(graph_node: Node) -> void: - selected_nodes[graph_node] = graph_node - last_edited_graph_node = graph_node - EditorInterface.get_inspector().edit(graph_node_to_blend_tree_node[graph_node]) + graph_node_to_blend_tree_node[graph_node].position = graph_node.position_offset func _on_blend_tree_graph_edit_node_deselected(graph_node: Node) -> void: @@ -247,6 +191,19 @@ func _on_blend_tree_graph_edit_node_deselected(graph_node: Node) -> void: selected_nodes.erase(graph_node) +func _on_blend_tree_graph_edit_node_selected(graph_node: Node) -> void: + selected_nodes[graph_node] = graph_node + last_selected_graph_node = graph_node + EditorInterface.get_inspector().edit(graph_node_to_blend_tree_node[graph_node]) + + +func _on_blend_tree_graph_edit_scroll_offset_changed(offset: Vector2) -> void: + blend_tree.graph_offset = offset + + +# +# AddNodePopupMenu +# func _on_blend_tree_graph_edit_popup_request(at_position: Vector2) -> void: add_node_popup_menu.position = get_screen_position() + get_local_mouse_position() add_node_popup_menu.reset_size() @@ -258,7 +215,7 @@ func _on_add_node_popup_menu_index_pressed(index: int) -> void: var new_blend_tree_node: BLTAnimationNode = ClassDB.instantiate(registered_nodes[index]) blend_tree.add_node(new_blend_tree_node) - var graph_node:GraphNode = create_node_for_blt_node(new_blend_tree_node) + var graph_node:GraphNode = create_graph_node_for_blt_node(new_blend_tree_node) blend_tree_graph_edit.add_child(graph_node) graph_node_to_blend_tree_node[graph_node] = new_blend_tree_node @@ -266,38 +223,23 @@ func _on_add_node_popup_menu_index_pressed(index: int) -> void: if new_node_position != Vector2.INF: graph_node.position_offset = new_node_position - new_blend_tree_node.graph_offset = new_node_position + new_blend_tree_node.position = new_node_position new_node_position = Vector2.INF -func _blend_tree_graph_edit_remove_node_connections(graph_node:GraphNode): - var node_connections:Array = [] +# +# Handle Node double click +# +func _on_node_gui_input(input_event:InputEvent, graph_node:GraphNode): + # print("Got input event on graph node %s!" % graph_node.name) - for connection:Dictionary in blend_tree_graph_edit.connections: - if connection["from_node"] == graph_node.name or connection["to_node"] == graph_node.name: - node_connections.append(connection) + var mouse_button_event:InputEventMouseButton = input_event as InputEventMouseButton + if mouse_button_event and mouse_button_event.double_click: + _on_node_double_click(graph_node) + +func _on_node_double_click(graph_node:GraphNode): + var blend_tree_node:BLTAnimationNode = graph_node_to_blend_tree_node[graph_node] - for node_connection:Dictionary in node_connections: - print("Removing connection %s" % str(node_connection)) - blend_tree_graph_edit.disconnect_node(node_connection["from_node"], node_connection["from_port"], node_connection["to_node"], node_connection["to_port"]) - - -func _on_blend_tree_graph_edit_disconnection_request(from_node: StringName, from_port: int, to_node: StringName, to_port: int) -> void: - print("removing connection") - - var blend_tree_source_node = blend_tree.get_node(from_node) - var blend_tree_target_node = blend_tree.get_node(to_node) - var target_port_name = blend_tree_target_node.get_input_names()[to_port] - blend_tree.remove_connection(blend_tree_source_node, blend_tree_target_node, target_port_name) - - blend_tree_graph_edit.disconnect_node(from_node, from_port, to_node, to_port) - - -func _trigger_animation_graph_initialize(node_name:StringName) -> void: - root_animation_node.node_changed.emit("root") - - -func _on_visibility_changed() -> void: - if visible and is_instance_valid(last_edited_graph_node): - _on_blend_tree_graph_edit_node_selected(last_edited_graph_node) + if blend_tree_node is BLTAnimationNodeBlendTree: + edit_subgraph.emit(blend_tree_node) diff --git a/demo/addons/blendalot/blend_tree_editor.gd.uid b/demo/addons/blendalot/blend_tree_editor.gd.uid new file mode 100644 index 0000000..c2a2a36 --- /dev/null +++ b/demo/addons/blendalot/blend_tree_editor.gd.uid @@ -0,0 +1 @@ +uid://dr0ndqekm21gy diff --git a/demo/addons/blendalot/blend_tree_editor.tscn b/demo/addons/blendalot/blend_tree_editor.tscn new file mode 100644 index 0000000..57e51a7 --- /dev/null +++ b/demo/addons/blendalot/blend_tree_editor.tscn @@ -0,0 +1,51 @@ +[gd_scene format=3 uid="uid://cptd46rpm0gl3"] + +[ext_resource type="Script" uid="uid://dr0ndqekm21gy" path="res://addons/blendalot/blend_tree_editor.gd" id="1_0srhh"] + +[node name="BlendTreeEditor" type="Control" unique_id=1313738200] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_0srhh") + +[node name="Panel" type="Panel" parent="." unique_id=758924321] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_vertical = 3 + +[node name="AddNodePopupMenu" type="PopupMenu" parent="Panel" unique_id=108570539] +unique_name_in_owner = true +oversampling_override = 1.0 +item_count = 3 +item_0/text = "BLTAnimationNodeSampler" +item_0/id = 0 +item_1/text = "BLTAnimationNodeBlend2" +item_1/id = 1 +item_2/text = "BLTAnimationNodeBlendTree" +item_2/id = 2 + +[node name="BlendTreeGraphEdit" type="GraphEdit" parent="Panel" unique_id=391120290] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +right_disconnects = true + +[connection signal="index_pressed" from="Panel/AddNodePopupMenu" to="." method="_on_add_node_popup_menu_index_pressed"] +[connection signal="connection_request" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_connection_request"] +[connection signal="delete_nodes_request" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_delete_nodes_request"] +[connection signal="end_node_move" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_end_node_move"] +[connection signal="node_deselected" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_node_deselected"] +[connection signal="node_selected" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_node_selected"] +[connection signal="popup_request" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_popup_request"] +[connection signal="scroll_offset_changed" from="Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_scroll_offset_changed"] diff --git a/demo/addons/blendalot/blendalot_main_panel.gd.uid b/demo/addons/blendalot/blendalot_main_panel.gd.uid deleted file mode 100644 index 40b1784..0000000 --- a/demo/addons/blendalot/blendalot_main_panel.gd.uid +++ /dev/null @@ -1 +0,0 @@ -uid://dvulvuytt81lw diff --git a/demo/addons/blendalot/blendalot_main_panel.tscn b/demo/addons/blendalot/blendalot_main_panel.tscn deleted file mode 100644 index bc0b98e..0000000 --- a/demo/addons/blendalot/blendalot_main_panel.tscn +++ /dev/null @@ -1,109 +0,0 @@ -[gd_scene format=3 uid="uid://31c6depvs0y1"] - -[ext_resource type="Script" uid="uid://dvulvuytt81lw" path="res://addons/blendalot/blendalot_main_panel.gd" id="1_427jg"] - -[node name="BlendalotMainPanel" type="Control" unique_id=1259518158] -layout_mode = 3 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -size_flags_horizontal = 3 -size_flags_vertical = 3 -script = ExtResource("1_427jg") - -[node name="BlendTreeEditorContainer" type="VBoxContainer" parent="." unique_id=2044593527] -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 - -[node name="HBoxContainer" type="HBoxContainer" parent="BlendTreeEditorContainer" unique_id=1742071203] -layout_mode = 2 - -[node name="ResetGraphButton" type="Button" parent="BlendTreeEditorContainer/HBoxContainer" unique_id=1060776498] -layout_mode = 2 -size_flags_horizontal = 0 -text = "Reset" - -[node name="FileNameLineEdit" type="LineEdit" parent="BlendTreeEditorContainer/HBoxContainer" unique_id=2033619565] -unique_name_in_owner = true -custom_minimum_size = Vector2(250, 0) -layout_mode = 2 -text = "editor_test_tree.tres" - -[node name="SaveButton" type="Button" parent="BlendTreeEditorContainer/HBoxContainer" unique_id=597228263] -layout_mode = 2 -size_flags_horizontal = 0 -text = "Save -" - -[node name="LoadButton" type="Button" parent="BlendTreeEditorContainer/HBoxContainer" unique_id=559146765] -layout_mode = 2 -size_flags_horizontal = 0 -text = "Load -" - -[node name="ReinitializeButton" type="Button" parent="BlendTreeEditorContainer/HBoxContainer" unique_id=719949205] -layout_mode = 2 -size_flags_horizontal = 0 -text = "Reinitialize" - -[node name="TreeOptionButton" type="OptionButton" parent="BlendTreeEditorContainer/HBoxContainer" unique_id=760974122] -unique_name_in_owner = true -layout_mode = 2 -selected = 0 -item_count = 2 -popup/item_0/text = "AnimationSampler" -popup/item_0/id = 1 -popup/item_1/text = "Blend2" -popup/item_1/id = 2 - -[node name="InstantiateTreeButton" type="Button" parent="BlendTreeEditorContainer/HBoxContainer" unique_id=127759440] -layout_mode = 2 -size_flags_horizontal = 0 -text = "Instantiate" - -[node name="Panel" type="Panel" parent="BlendTreeEditorContainer" unique_id=424652158] -layout_mode = 2 -size_flags_vertical = 3 - -[node name="AddNodePopupMenu" type="PopupMenu" parent="BlendTreeEditorContainer/Panel" unique_id=2020489213] -unique_name_in_owner = true -oversampling_override = 1.0 -item_count = 3 -item_0/text = "BLTAnimationNodeSampler" -item_0/id = 0 -item_1/text = "BLTAnimationNodeBlend2" -item_1/id = 1 -item_2/text = "BLTAnimationNodeBlendTree" -item_2/id = 2 - -[node name="BlendTreeGraphEdit" type="GraphEdit" parent="BlendTreeEditorContainer/Panel" unique_id=387715755] -unique_name_in_owner = true -layout_mode = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -grow_horizontal = 2 -grow_vertical = 2 -right_disconnects = true - -[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"] -[connection signal="pressed" from="BlendTreeEditorContainer/HBoxContainer/ResetGraphButton" to="." method="_on_reset_graph_button_pressed"] -[connection signal="pressed" from="BlendTreeEditorContainer/HBoxContainer/SaveButton" to="." method="_on_save_button_pressed"] -[connection signal="pressed" from="BlendTreeEditorContainer/HBoxContainer/LoadButton" to="." method="_on_load_button_pressed"] -[connection signal="pressed" from="BlendTreeEditorContainer/HBoxContainer/ReinitializeButton" to="." method="_trigger_animation_graph_initialize"] -[connection signal="pressed" from="BlendTreeEditorContainer/HBoxContainer/InstantiateTreeButton" to="." method="_on_instantiate_tree_button_pressed"] -[connection signal="index_pressed" from="BlendTreeEditorContainer/Panel/AddNodePopupMenu" to="." method="_on_add_node_popup_menu_index_pressed"] -[connection signal="begin_node_move" from="BlendTreeEditorContainer/Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_begin_node_move"] -[connection signal="connection_request" from="BlendTreeEditorContainer/Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_connection_request"] -[connection signal="delete_nodes_request" from="BlendTreeEditorContainer/Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_delete_nodes_request"] -[connection signal="disconnection_request" from="BlendTreeEditorContainer/Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_disconnection_request"] -[connection signal="end_node_move" from="BlendTreeEditorContainer/Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_end_node_move"] -[connection signal="node_deselected" from="BlendTreeEditorContainer/Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_node_deselected"] -[connection signal="node_selected" from="BlendTreeEditorContainer/Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_node_selected"] -[connection signal="popup_request" from="BlendTreeEditorContainer/Panel/BlendTreeGraphEdit" to="." method="_on_blend_tree_graph_edit_popup_request"] diff --git a/demo/addons/blendalot/blendalot_plugin.gd b/demo/addons/blendalot/blendalot_plugin.gd index 24572d3..b58122f 100644 --- a/demo/addons/blendalot/blendalot_plugin.gd +++ b/demo/addons/blendalot/blendalot_plugin.gd @@ -1,9 +1,8 @@ @tool extends EditorPlugin -const MainPanel = preload("res://addons/blendalot/blendalot_main_panel.tscn") - -var main_panel_instance:BlendalotMainPanel +var editor_dock:EditorDock = null +var animation_graph_editor:AnimationGraphEditor = null func _enable_plugin() -> void: # Add autoloads here. @@ -16,25 +15,29 @@ func _disable_plugin() -> void: func _enter_tree() -> void: - main_panel_instance = MainPanel.instantiate() - # Add the main panel to the editor's main viewport. - EditorInterface.get_editor_main_screen().add_child(main_panel_instance) - # Hide the main panel. Very much required. - _make_visible(false) + editor_dock = EditorDock.new() + editor_dock.title = "Animation Graph" + editor_dock.default_slot = EditorDock.DOCK_SLOT_BOTTOM + animation_graph_editor = preload ("res://addons/blendalot/animation_graph_editor.tscn").instantiate() + editor_dock.add_child(animation_graph_editor) + add_dock(editor_dock) func _exit_tree() -> void: - if main_panel_instance: - main_panel_instance.queue_free() + remove_dock(editor_dock) + editor_dock.queue_free() + editor_dock = null + + animation_graph_editor.queue_free() + animation_graph_editor = null -func _has_main_screen(): - return true +func _has_main_screen() -> bool: + return false func _make_visible(visible): - if main_panel_instance: - main_panel_instance.visible = visible + pass func _get_plugin_name(): @@ -48,9 +51,14 @@ func _get_plugin_icon(): func _handles(obj: Object) -> bool: return obj is BLTAnimationNodeBlendTree + func _edit(object: Object): + if not is_instance_valid(animation_graph_editor): + push_error("Cannot edit object as AnimationGraphEditor is not initialized") + return + if object is BLTAnimationNodeBlendTree: - main_panel_instance.edit_blend_tree(object) + animation_graph_editor.edit_animation_root_node(object) return print("Cannot (yet) edit object " + str(object)) diff --git a/demo/main.tscn b/demo/main.tscn index c7c61c5..036b08e 100644 --- a/demo/main.tscn +++ b/demo/main.tscn @@ -31,28 +31,38 @@ sky = SubResource("Sky_1bvp3") tonemap_mode = 2 glow_enabled = true -[sub_resource type="BLTAnimationNodeBlend2" id="BLTAnimationNodeBlend2_bvt3d"] +[sub_resource type="BLTAnimationNodeBlend2" id="BLTAnimationNodeBlend2_7mycd"] resource_name = "BLTAnimationNodeBlend2" -graph_offset = Vector2(-540, -120) +position = Vector2(-320, -40) -[sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_sntl5"] -resource_name = "BLTAnimationNodeSampler 1" -graph_offset = Vector2(-1120, 180) -animation = &"animation_library/Run-InPlace" - -[sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_n4m28"] +[sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_272bh"] resource_name = "BLTAnimationNodeSampler" -graph_offset = Vector2(-1120, -280) +position = Vector2(-490, 7) +animation = &"animation_library/Walk-InPlace" + +[sub_resource type="BLTAnimationNodeBlendTree" id="BLTAnimationNodeBlendTree_5vw27"] +resource_name = "BLTAnimationNodeBlendTree" +position = Vector2(-640, -20) +graph_offset = Vector2(-766.67163, -102.823944) +nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_272bh") +nodes/BLTAnimationNodeSampler/graph_offset = Vector2(-490, 7) +node_connections = ["Output", 0, "BLTAnimationNodeSampler"] + +[sub_resource type="BLTAnimationNodeSampler" id="BLTAnimationNodeSampler_kek77"] +resource_name = "BLTAnimationNodeSampler" +position = Vector2(-620, 140) animation = &"animation_library/Walk-InPlace" [sub_resource type="BLTAnimationNodeBlendTree" id="BLTAnimationNodeBlendTree_7mycd"] -nodes/BLTAnimationNodeBlend2/node = SubResource("BLTAnimationNodeBlend2_bvt3d") -nodes/BLTAnimationNodeBlend2/graph_offset = Vector2(-540, -120) -"nodes/BLTAnimationNodeSampler 1/node" = SubResource("BLTAnimationNodeSampler_sntl5") -"nodes/BLTAnimationNodeSampler 1/graph_offset" = Vector2(-1120, 180) -nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_n4m28") -nodes/BLTAnimationNodeSampler/graph_offset = Vector2(-1120, -280) -node_connections = ["BLTAnimationNodeBlend2", 0, "BLTAnimationNodeSampler", "BLTAnimationNodeBlend2", 1, "BLTAnimationNodeSampler 1", "Output", 0, "BLTAnimationNodeBlend2"] +resource_name = "Root" +graph_offset = Vector2(-1054.4585, -50.771484) +nodes/BLTAnimationNodeBlend2/node = SubResource("BLTAnimationNodeBlend2_7mycd") +nodes/BLTAnimationNodeBlend2/graph_offset = Vector2(-320, -40) +nodes/BLTAnimationNodeSampler/node = SubResource("BLTAnimationNodeSampler_kek77") +nodes/BLTAnimationNodeSampler/graph_offset = Vector2(-620, 140) +nodes/BLTAnimationNodeBlendTree/node = SubResource("BLTAnimationNodeBlendTree_5vw27") +nodes/BLTAnimationNodeBlendTree/graph_offset = Vector2(-640, -20) +node_connections = ["Output", 0, "BLTAnimationNodeBlend2", "BLTAnimationNodeBlend2", 0, "BLTAnimationNodeBlendTree", "BLTAnimationNodeBlend2", 1, "BLTAnimationNodeSampler"] [node name="Main" type="Node3D" unique_id=933302313] script = ExtResource("1_1bvp3") @@ -159,6 +169,7 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.6, 0, 0) tree_root = ExtResource("6_5vw27") anim_player = NodePath("../AnimationPlayer") parameters/Blend2/blend_amount = 0.0 +parameters/BlendTree/Blend2/blend_amount = 0.0 [node name="MixamoAmyWalkLimpSynced" parent="Characters" unique_id=1018815116 instance=ExtResource("1_0xm2m")] unique_name_in_owner = true @@ -177,127 +188,126 @@ parameters/BLTAnimationNodeBlend2/blend_amount = 1.0 unique_name_in_owner = true transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.4, 0, 0) -[node name="Skeleton3D" parent="Characters/MixamoAmyWalkRunSynced/Armature" parent_id_path=PackedInt32Array(2088190993, 52334938) index="0" unique_id=2014991417] -bones/0/position = Vector3(1.2535723, 103.23205, 0) -bones/2/position = Vector3(1.2545489, -1.2283401, -63.87065) -bones/2/rotation = Quaternion(-0.68592405, 0.04377775, -0.051641874, 0.724517) -bones/3/position = Vector3(1.8626451e-08, 3.9624305, -0.274297) -bones/3/rotation = Quaternion(-0.022852536, -0.012121664, 0.0041041635, 0.99965584) -bones/4/position = Vector3(5.9604645e-08, 14.123348, 0.2644268) -bones/4/rotation = Quaternion(-0.004333934, -0.027048457, 0.008698374, 0.99958694) -bones/5/position = Vector3(3.7252903e-08, 11.404536, 0.106110305) -bones/5/rotation = Quaternion(-0.0043339357, -0.027048472, 0.008698381, 0.99958694) -bones/6/position = Vector3(2.9802322e-08, 9.946667, 1.6090326e-08) -bones/6/rotation = Quaternion(0.01833006, 0.009223348, -0.022252144, 0.99954194) -bones/7/position = Vector3(3.1292439e-07, 8.579114, 0.11416777) -bones/7/rotation = Quaternion(0.012213917, 0.0008427718, 0.018853437, 0.99974734) -bones/8/position = Vector3(1.8626451e-09, 25.089184, 0.33387405) -bones/9/position = Vector3(4.22409, 8.898366, -0.056614783) -bones/9/rotation = Quaternion(0.6974001, 0.2956288, -0.5221589, 0.39190146) -bones/10/position = Vector3(7.763405e-07, 8.86101, -1.885943e-05) -bones/10/rotation = Quaternion(0.26628703, -0.06642532, 0.008976073, 0.9615604) -bones/11/position = Vector3(-6.736064e-08, 18.975187, -5.359281e-06) -bones/11/rotation = Quaternion(0.07033256, 0.12871316, 0.46235967, 0.8744769) -bones/12/position = Vector3(2.0505329e-06, 19.896036, 4.198435e-06) -bones/12/rotation = Quaternion(-0.16744098, 0.1057004, 0.06551589, 0.97800744) -bones/13/position = Vector3(-2.0888743, 2.1412597, 1.2094326) -bones/13/rotation = Quaternion(0.25766087, -0.0057431525, 0.24790713, 0.93387365) -bones/14/position = Vector3(-0.3297696, 2.5601492, 5.6111962e-06) -bones/14/rotation = Quaternion(-0.02088847, -0.0012659901, -0.06479406, 0.9976792) -bones/15/position = Vector3(0.07692051, 2.7271638, -7.698024e-07) -bones/15/rotation = Quaternion(0.041175473, -5.169663e-07, -3.3207877e-07, 0.99915195) -bones/16/position = Vector3(0.25285125, 2.2376482, -2.5033949e-06) -bones/17/position = Vector3(-2.5860305, 6.9422946, 0.029643927) -bones/17/rotation = Quaternion(0.34374678, 0.015888449, 0.085352995, 0.9350405) -bones/18/position = Vector3(0.0010065138, 2.844871, 2.6222544e-05) -bones/18/rotation = Quaternion(0.57630825, -0.010742382, 0.057439517, 0.8151404) -bones/19/position = Vector3(-0.001300633, 2.6654923, -3.370296e-06) -bones/19/rotation = Quaternion(0.0067229928, -1.8172469e-07, -1.12402185e-08, 0.9999774) -bones/20/position = Vector3(0.00029665232, 2.2974284, 2.6011842e-06) -bones/21/position = Vector3(-0.81500757, 6.8271494, -0.11008961) -bones/21/rotation = Quaternion(0.4686701, -0.026470345, 0.09011306, 0.87836635) -bones/22/position = Vector3(-0.011725575, 3.256784, 9.871595e-06) -bones/22/rotation = Quaternion(0.7447584, -0.008458963, 0.08384082, 0.66199255) -bones/23/position = Vector3(-0.00070961565, 3.1778917, -4.440292e-06) -bones/23/rotation = Quaternion(0.05807299, -2.1569534e-08, -4.8931874e-08, 0.99831235) -bones/24/position = Vector3(0.012437165, 2.6951318, 2.2368273e-05) -bones/25/position = Vector3(0.89882326, 6.7787366, -0.023027958) -bones/25/rotation = Quaternion(0.46021903, -0.10865909, 0.0012826431, 0.88113) -bones/26/position = Vector3(-0.0040293336, 2.958041, 1.3685599e-05) -bones/26/rotation = Quaternion(0.75350595, 0.003054577, 0.06509644, 0.65420324) -bones/27/position = Vector3(0.0024927258, 2.756927, -1.8636636e-05) -bones/27/rotation = Quaternion(-0.0033205294, 3.9059813e-08, 6.5682637e-09, 0.9999945) -bones/28/position = Vector3(0.0015397072, 2.3345788, 1.1771219e-05) -bones/29/position = Vector3(2.5022223, 6.3907866, 0.08744741) -bones/29/rotation = Quaternion(0.5563202, -0.15497696, -0.0049168295, 0.81637365) -bones/30/position = Vector3(0.0032016933, 2.6237173, 5.5511973e-06) -bones/30/rotation = Quaternion(0.6839778, 0.025319714, 0.05863921, 0.72670126) -bones/31/position = Vector3(0.003878951, 2.1320877, -1.2886679e-06) -bones/31/rotation = Quaternion(-0.06925962, -1.0360488e-07, -7.0190005e-08, 0.9975987) -bones/32/position = Vector3(-0.0070759356, 1.7932303, -8.8289596e-07) -bones/33/position = Vector3(-4.2240915, 8.897269, -0.030230172) -bones/33/rotation = Quaternion(0.6396871, -0.34111822, 0.60846674, 0.32281098) -bones/34/position = Vector3(9.327891e-07, 8.8610115, -9.847447e-06) -bones/34/rotation = Quaternion(0.3631728, -0.04426816, 0.26242447, 0.892905) -bones/35/position = Vector3(6.476337e-07, 18.973557, 5.8403616e-06) -bones/35/rotation = Quaternion(0.020210672, -0.1976225, -0.21386963, 0.95645) -bones/36/position = Vector3(-7.630494e-08, 19.89834, -1.8180976e-06) -bones/36/rotation = Quaternion(-0.0013729627, -0.10906849, 0.07843006, 0.9909344) -bones/37/position = Vector3(2.0620086, 2.1477072, 1.2410417) -bones/37/rotation = Quaternion(0.2022776, 0.03663972, -0.31487894, 0.9266028) -bones/38/position = Vector3(0.2744484, 2.5658755, 3.7584634e-06) -bones/38/rotation = Quaternion(0.10343577, -0.19018154, 0.15068975, 0.9645852) -bones/39/position = Vector3(-0.076725245, 2.730221, -7.234994e-06) -bones/39/rotation = Quaternion(0.037325032, -2.1781963e-08, 1.19075e-07, 0.99930316) -bones/40/position = Vector3(-0.19772077, 2.2442596, 9.685756e-06) -bones/41/position = Vector3(2.5699375, 7.0537868, 0.05093465) -bones/41/rotation = Quaternion(0.33546335, 0.008294326, -0.03227234, 0.9414638) -bones/42/position = Vector3(-0.0015108623, 2.816315, -9.529522e-06) -bones/42/rotation = Quaternion(0.5038074, 0.025462631, -0.03289526, 0.86281383) -bones/43/position = Vector3(0.0011758618, 2.6396425, 2.472788e-06) -bones/43/rotation = Quaternion(0.0026853334, 3.311302e-08, -5.8677845e-08, 0.9999965) -bones/44/position = Vector3(0.00033191964, 2.2415001, 1.3194513e-06) -bones/45/position = Vector3(0.76549155, 7.018211, -0.09038047) -bones/45/rotation = Quaternion(0.365633, 0.035192948, -0.020985998, 0.92985666) -bones/46/position = Vector3(0.008488461, 3.3401706, -6.017696e-06) -bones/46/rotation = Quaternion(0.60296637, 0.037562832, -0.043432355, 0.79569733) -bones/47/position = Vector3(-0.007900611, 3.0566626, 5.4270527e-06) -bones/47/rotation = Quaternion(-0.027461762, -2.0760188e-08, 5.6872928e-08, 0.9996229) -bones/48/position = Vector3(-0.00058989227, 2.63951, 9.457464e-06) -bones/49/position = Vector3(-0.8923034, 6.9110794, -0.12160769) -bones/49/rotation = Quaternion(0.373129, 0.027513513, 0.0016994111, 0.92736983) -bones/50/position = Vector3(-0.00297606, 2.923956, 1.7109673e-05) -bones/50/rotation = Quaternion(0.5844741, -0.018550195, -0.061117128, 0.80889475) -bones/51/position = Vector3(0.0026345253, 2.717951, -5.427028e-06) -bones/51/rotation = Quaternion(0.009096339, 7.025756e-08, 2.6579988e-08, 0.99995863) -bones/52/position = Vector3(0.0003426671, 2.379634, 1.4747493e-06) -bones/53/position = Vector3(-2.4431183, 6.453577, 0.12551774) -bones/53/rotation = Quaternion(0.33751208, 0.021386249, -0.009726644, 0.941028) -bones/54/position = Vector3(-0.0026362836, 2.6278691, 4.2827646e-06) -bones/54/rotation = Quaternion(0.64713013, -0.039810352, -0.090106204, 0.75598854) -bones/55/position = Vector3(-0.001860708, 2.1224687, 9.940322e-07) -bones/55/rotation = Quaternion(-0.03619139, -1.1229469e-07, 2.121775e-08, 0.9993449) -bones/56/position = Vector3(0.004502952, 1.7919822, 1.2924895e-05) -bones/57/position = Vector3(7.557004, -4.826265, 0.30053553) -bones/57/rotation = Quaternion(-0.08986163, 0.021308435, -0.99325967, 0.070043266) -bones/58/position = Vector3(-0.124621816, 24.06574, 0.10470339) -bones/58/rotation = Quaternion(-0.4013793, 0.12247081, -0.016882984, 0.9075299) -bones/59/position = Vector3(-0.0060171685, 33.063114, 0.00394835) -bones/59/rotation = Quaternion(0.43592802, 0.023901237, 0.044110287, 0.89858204) -bones/60/position = Vector3(-0.0052775713, 12.893309, -0.5155027) -bones/60/rotation = Quaternion(0.5547358, -0.05625008, 0.006090132, 0.83010066) -bones/61/position = Vector3(0.014227723, 6.420835, 0.007887725) -bones/62/position = Vector3(-7.557004, -4.826261, 0.30053535) -bones/62/rotation = Quaternion(-0.0453176, 0.37578616, 0.92547935, 0.014799355) -bones/63/position = Vector3(0.12476807, 24.070103, -0.14491707) -bones/63/rotation = Quaternion(-0.27188188, -0.00034630176, 0.0028924432, 0.96232617) -bones/64/position = Vector3(0.0060205855, 33.063133, 0.004499323) -bones/64/rotation = Quaternion(0.4376588, -0.0021246495, 3.749458e-05, 0.8991387) -bones/65/position = Vector3(0.005378528, 12.718271, -0.52236915) -bones/65/rotation = Quaternion(0.34835225, 0.017514596, -0.0044682953, 0.9371894) -bones/66/position = Vector3(-0.014239848, 6.412128, 0.0079107955) +[node name="Skeleton3D" parent="Characters/MixamoAmyWalkRunSynced/Armature" parent_id_path=PackedInt32Array(2088190993, 1791722621) index="0" unique_id=1831928682] +bones/2/position = Vector3(0, 0, 0) +bones/2/rotation = Quaternion(0, 0, 0, 1) +bones/3/position = Vector3(0, 0, 0) +bones/3/rotation = Quaternion(0, 0, 0, 1) +bones/4/position = Vector3(0, 0, 0) +bones/4/rotation = Quaternion(0, 0, 0, 1) +bones/5/position = Vector3(0, 0, 0) +bones/5/rotation = Quaternion(0, 0, 0, 1) +bones/6/position = Vector3(0, 0, 0) +bones/6/rotation = Quaternion(0, 0, 0, 1) +bones/7/position = Vector3(0, 0, 0) +bones/7/rotation = Quaternion(0, 0, 0, 1) +bones/8/position = Vector3(0, 0, 0) +bones/9/position = Vector3(0, 0, 0) +bones/9/rotation = Quaternion(0, 0, 0, 1) +bones/10/position = Vector3(0, 0, 0) +bones/10/rotation = Quaternion(0, 0, 0, 1) +bones/11/position = Vector3(0, 0, 0) +bones/11/rotation = Quaternion(0, 0, 0, 1) +bones/12/position = Vector3(0, 0, 0) +bones/12/rotation = Quaternion(0, 0, 0, 1) +bones/13/position = Vector3(0, 0, 0) +bones/13/rotation = Quaternion(0, 0, 0, 1) +bones/14/position = Vector3(0, 0, 0) +bones/14/rotation = Quaternion(0, 0, 0, 1) +bones/15/position = Vector3(0, 0, 0) +bones/15/rotation = Quaternion(0, 0, 0, 1) +bones/16/position = Vector3(0, 0, 0) +bones/17/position = Vector3(0, 0, 0) +bones/17/rotation = Quaternion(0, 0, 0, 1) +bones/18/position = Vector3(0, 0, 0) +bones/18/rotation = Quaternion(0, 0, 0, 1) +bones/19/position = Vector3(0, 0, 0) +bones/19/rotation = Quaternion(0, 0, 0, 1) +bones/20/position = Vector3(0, 0, 0) +bones/21/position = Vector3(0, 0, 0) +bones/21/rotation = Quaternion(0, 0, 0, 1) +bones/22/position = Vector3(0, 0, 0) +bones/22/rotation = Quaternion(0, 0, 0, 1) +bones/23/position = Vector3(0, 0, 0) +bones/23/rotation = Quaternion(0, 0, 0, 1) +bones/24/position = Vector3(0, 0, 0) +bones/25/position = Vector3(0, 0, 0) +bones/25/rotation = Quaternion(0, 0, 0, 1) +bones/26/position = Vector3(0, 0, 0) +bones/26/rotation = Quaternion(0, 0, 0, 1) +bones/27/position = Vector3(0, 0, 0) +bones/27/rotation = Quaternion(0, 0, 0, 1) +bones/28/position = Vector3(0, 0, 0) +bones/29/position = Vector3(0, 0, 0) +bones/29/rotation = Quaternion(0, 0, 0, 1) +bones/30/position = Vector3(0, 0, 0) +bones/30/rotation = Quaternion(0, 0, 0, 1) +bones/31/position = Vector3(0, 0, 0) +bones/31/rotation = Quaternion(0, 0, 0, 1) +bones/32/position = Vector3(0, 0, 0) +bones/33/position = Vector3(0, 0, 0) +bones/33/rotation = Quaternion(0, 0, 0, 1) +bones/34/position = Vector3(0, 0, 0) +bones/34/rotation = Quaternion(0, 0, 0, 1) +bones/35/position = Vector3(0, 0, 0) +bones/35/rotation = Quaternion(0, 0, 0, 1) +bones/36/position = Vector3(0, 0, 0) +bones/36/rotation = Quaternion(0, 0, 0, 1) +bones/37/position = Vector3(0, 0, 0) +bones/37/rotation = Quaternion(0, 0, 0, 1) +bones/38/position = Vector3(0, 0, 0) +bones/38/rotation = Quaternion(0, 0, 0, 1) +bones/39/position = Vector3(0, 0, 0) +bones/39/rotation = Quaternion(0, 0, 0, 1) +bones/40/position = Vector3(0, 0, 0) +bones/41/position = Vector3(0, 0, 0) +bones/41/rotation = Quaternion(0, 0, 0, 1) +bones/42/position = Vector3(0, 0, 0) +bones/42/rotation = Quaternion(0, 0, 0, 1) +bones/43/position = Vector3(0, 0, 0) +bones/43/rotation = Quaternion(0, 0, 0, 1) +bones/44/position = Vector3(0, 0, 0) +bones/45/position = Vector3(0, 0, 0) +bones/45/rotation = Quaternion(0, 0, 0, 1) +bones/46/position = Vector3(0, 0, 0) +bones/46/rotation = Quaternion(0, 0, 0, 1) +bones/47/position = Vector3(0, 0, 0) +bones/47/rotation = Quaternion(0, 0, 0, 1) +bones/48/position = Vector3(0, 0, 0) +bones/49/position = Vector3(0, 0, 0) +bones/49/rotation = Quaternion(0, 0, 0, 1) +bones/50/position = Vector3(0, 0, 0) +bones/50/rotation = Quaternion(0, 0, 0, 1) +bones/51/position = Vector3(0, 0, 0) +bones/51/rotation = Quaternion(0, 0, 0, 1) +bones/52/position = Vector3(0, 0, 0) +bones/53/position = Vector3(0, 0, 0) +bones/53/rotation = Quaternion(0, 0, 0, 1) +bones/54/position = Vector3(0, 0, 0) +bones/54/rotation = Quaternion(0, 0, 0, 1) +bones/55/position = Vector3(0, 0, 0) +bones/55/rotation = Quaternion(0, 0, 0, 1) +bones/56/position = Vector3(0, 0, 0) +bones/57/position = Vector3(0, 0, 0) +bones/57/rotation = Quaternion(0, 0, 0, 1) +bones/58/position = Vector3(0, 0, 0) +bones/58/rotation = Quaternion(0, 0, 0, 1) +bones/59/position = Vector3(0, 0, 0) +bones/59/rotation = Quaternion(0, 0, 0, 1) +bones/60/position = Vector3(0, 0, 0) +bones/60/rotation = Quaternion(0, 0, 0, 1) +bones/61/position = Vector3(0, 0, 0) +bones/62/position = Vector3(0, 0, 0) +bones/62/rotation = Quaternion(0, 0, 0, 1) +bones/63/position = Vector3(0, 0, 0) +bones/63/rotation = Quaternion(0, 0, 0, 1) +bones/64/position = Vector3(0, 0, 0) +bones/64/rotation = Quaternion(0, 0, 0, 1) +bones/65/position = Vector3(0, 0, 0) +bones/65/rotation = Quaternion(0, 0, 0, 1) +bones/66/position = Vector3(0, 0, 0) -[node name="AnimationPlayer" parent="Characters/MixamoAmyWalkRunSynced" index="1" unique_id=945472897] +[node name="AnimationPlayer" parent="Characters/MixamoAmyWalkRunSynced" index="1" unique_id=66984852] active = false [node name="AnimationPlayer2" type="AnimationPlayer" parent="Characters/MixamoAmyWalkRunSynced" unique_id=1255239074]