feature/blend_tree_editor #1

Open
martin wants to merge 29 commits from feature/blend_tree_editor into main
12 changed files with 567 additions and 449 deletions
Showing only changes of commit be6e021198 - Show all commits

View File

@ -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;
}

View File

@ -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<StringName> 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<Ref<BLTAnimationNode>> input_nodes;
LocalVector<AnimationData *> input_data;
@ -604,6 +607,14 @@ public:
};
LocalVector<NodeRuntimeData> _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<BLTAnimationNode> &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<BLTAnimationNode> &input_node : node_runtime_data.input_nodes) {
if (!input_node.is_valid()) {
return false;
}
}
}
tree_initialized = true;
return true;

View File

@ -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)

View File

@ -0,0 +1 @@
uid://bxxipuj2s5gxu

View File

@ -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

View File

@ -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 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
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 _on_save_button_pressed() -> void:
ResourceSaver.save(blend_tree, "res://" + file_name_line_edit.text)
func _trigger_graph_changed():
graph_changed.emit()
func _on_load_button_pressed() -> void:
var loaded_blend_tree:BLTAnimationNodeBlendTree = ResourceLoader.load("res://" + file_name_line_edit.text, "BLTAnimationNodeBlendTree", 0)
func _remove_node_connections(graph_node:GraphNode):
var node_connections:Array = []
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)
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()
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)
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_node_double_click(graph_node:GraphNode):
var blend_tree_node:BLTAnimationNode = graph_node_to_blend_tree_node[graph_node]
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)

View File

@ -0,0 +1 @@
uid://dr0ndqekm21gy

View File

@ -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"]

View File

@ -1 +0,0 @@
uid://dvulvuytt81lw

View File

@ -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"]

View File

@ -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))

View File

@ -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]