Display and allow setting name/index of BlendSpace points
This commit is contained in:
parent
778cf54dab
commit
f873fa3c3a
13 changed files with 1244 additions and 179 deletions
|
|
@ -17,8 +17,17 @@
|
|||
<param index="0" name="node" type="AnimationRootNode" />
|
||||
<param index="1" name="pos" type="float" />
|
||||
<param index="2" name="at_index" type="int" default="-1" />
|
||||
<param index="3" name="name" type="StringName" default="&""" />
|
||||
<description>
|
||||
Adds a new point that represents a [param node] on the virtual axis at a given position set by [param pos]. You can insert it at a specific index using the [param at_index] argument. If you use the default value for [param at_index], the point is inserted at the end of the blend points array.
|
||||
Adds a new point with [param name] that represents a [param node] on the virtual axis at a given position set by [param pos]. You can insert it at a specific index using the [param at_index] argument. If you use the default value for [param at_index], the point is inserted at the end of the blend points array.
|
||||
[b]Note:[/b] If no name is provided, safe index is used as reference. In the future, empty names will be deprecated, so explicitly passing a name is recommended.
|
||||
</description>
|
||||
</method>
|
||||
<method name="find_blend_point_by_name" qualifiers="const">
|
||||
<return type="int" />
|
||||
<param index="0" name="name" type="StringName" />
|
||||
<description>
|
||||
Returns the index of the blend point with the given [param name]. Returns [code]-1[/code] if no blend point with that name is found.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_blend_point_count" qualifiers="const">
|
||||
|
|
@ -27,6 +36,13 @@
|
|||
Returns the number of points on the blend axis.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_blend_point_name" qualifiers="const">
|
||||
<return type="StringName" />
|
||||
<param index="0" name="point" type="int" />
|
||||
<description>
|
||||
Returns the name of the blend point at index [param point].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_blend_point_node" qualifiers="const">
|
||||
<return type="AnimationRootNode" />
|
||||
<param index="0" name="point" type="int" />
|
||||
|
|
@ -48,6 +64,22 @@
|
|||
Removes the point at index [param point] from the blend axis.
|
||||
</description>
|
||||
</method>
|
||||
<method name="reorder_blend_point">
|
||||
<return type="void" />
|
||||
<param index="0" name="from_index" type="int" />
|
||||
<param index="1" name="to_index" type="int" />
|
||||
<description>
|
||||
Swaps the blend points at indices [param from_index] and [param to_index], exchanging their positions and properties.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_blend_point_name">
|
||||
<return type="void" />
|
||||
<param index="0" name="point" type="int" />
|
||||
<param index="1" name="name" type="StringName" />
|
||||
<description>
|
||||
Sets the name of the blend point at index [param point]. If the name conflicts with an existing point, a unique name will be generated automatically.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_blend_point_node">
|
||||
<return type="void" />
|
||||
<param index="0" name="point" type="int" />
|
||||
|
|
|
|||
|
|
@ -18,8 +18,10 @@
|
|||
<param index="0" name="node" type="AnimationRootNode" />
|
||||
<param index="1" name="pos" type="Vector2" />
|
||||
<param index="2" name="at_index" type="int" default="-1" />
|
||||
<param index="3" name="name" type="StringName" default="&""" />
|
||||
<description>
|
||||
Adds a new point that represents a [param node] at the position set by [param pos]. You can insert it at a specific index using the [param at_index] argument. If you use the default value for [param at_index], the point is inserted at the end of the blend points array.
|
||||
Adds a new point with [param name] that represents a [param node] at the position set by [param pos]. You can insert it at a specific index using the [param at_index] argument. If you use the default value for [param at_index], the point is inserted at the end of the blend points array.
|
||||
[b]Note:[/b] If no name is provided, safe index is used as reference. In the future, empty names will be deprecated, so explicitly passing a name is recommended.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_triangle">
|
||||
|
|
@ -32,12 +34,26 @@
|
|||
Creates a new triangle using three points [param x], [param y], and [param z]. Triangles can overlap. You can insert the triangle at a specific index using the [param at_index] argument. If you use the default value for [param at_index], the point is inserted at the end of the blend points array.
|
||||
</description>
|
||||
</method>
|
||||
<method name="find_blend_point_by_name" qualifiers="const">
|
||||
<return type="int" />
|
||||
<param index="0" name="name" type="StringName" />
|
||||
<description>
|
||||
Returns the index of the blend point with the given [param name]. Returns [code]-1[/code] if no blend point with that name is found.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_blend_point_count" qualifiers="const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Returns the number of points in the blend space.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_blend_point_name" qualifiers="const">
|
||||
<return type="StringName" />
|
||||
<param index="0" name="point" type="int" />
|
||||
<description>
|
||||
Returns the name of the blend point at index [param point].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_blend_point_node" qualifiers="const">
|
||||
<return type="AnimationRootNode" />
|
||||
<param index="0" name="point" type="int" />
|
||||
|
|
@ -80,6 +96,22 @@
|
|||
Removes the triangle at index [param triangle] from the blend space.
|
||||
</description>
|
||||
</method>
|
||||
<method name="reorder_blend_point">
|
||||
<return type="void" />
|
||||
<param index="0" name="from_index" type="int" />
|
||||
<param index="1" name="to_index" type="int" />
|
||||
<description>
|
||||
Swaps the blend points at indices [param from_index] and [param to_index], exchanging their positions and properties.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_blend_point_name">
|
||||
<return type="void" />
|
||||
<param index="0" name="point" type="int" />
|
||||
<param index="1" name="name" type="StringName" />
|
||||
<description>
|
||||
Sets the name of the blend point at index [param point]. If the name conflicts with an existing point, a unique name will be generated automatically.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_blend_point_node">
|
||||
<return type="void" />
|
||||
<param index="0" name="point" type="int" />
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@
|
|||
#include "scene/gui/panel_container.h"
|
||||
#include "scene/gui/separator.h"
|
||||
#include "scene/gui/spin_box.h"
|
||||
#include "scene/main/timer.h"
|
||||
|
||||
StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {
|
||||
StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + "blend_position";
|
||||
|
|
@ -60,12 +61,20 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
|
||||
Ref<InputEventKey> k = p_event;
|
||||
|
||||
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
|
||||
if (selected_point != -1) {
|
||||
if (!read_only) {
|
||||
_erase_selected();
|
||||
}
|
||||
if (k.is_valid() && k->is_pressed() && !k->is_echo()) {
|
||||
if (k->get_keycode() == Key::ESCAPE && editing_point != -1) {
|
||||
_cancel_inline_edit();
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
|
||||
if (tool_select->is_pressed() && k->get_keycode() == Key::KEY_DELETE) {
|
||||
if (selected_point != -1) {
|
||||
if (!read_only) {
|
||||
_erase_selected();
|
||||
}
|
||||
accept_event();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -128,16 +137,26 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
blend_space_draw->queue_redraw(); // why not
|
||||
|
||||
// try to see if a point can be selected
|
||||
selected_point = -1;
|
||||
_update_tool_erase();
|
||||
_set_selected_point(-1);
|
||||
|
||||
// Check if clicking on text areas first.
|
||||
for (int i = 0; i < text_rects.size(); i++) {
|
||||
if (text_rects[i].has_point(mb->get_position())) {
|
||||
_set_selected_point(i);
|
||||
|
||||
dragging_selected_attempt = true;
|
||||
drag_from = mb->get_position();
|
||||
_update_edited_point_name();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Then check point positions.
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
if (Math::abs(float(points[i] - mb->get_position().x)) < 10 * EDSCALE) {
|
||||
selected_point = i;
|
||||
_set_selected_point(i);
|
||||
|
||||
Ref<AnimationNode> node = blend_space->get_blend_point_node(i);
|
||||
EditorNode::get_singleton()->push_item(node.ptr(), "", true);
|
||||
|
||||
if (mb->is_double_click() && AnimationTreeEditor::get_singleton()->can_edit(node)) {
|
||||
_open_editor();
|
||||
return;
|
||||
|
|
@ -145,19 +164,24 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
|
||||
dragging_selected_attempt = true;
|
||||
drag_from = mb->get_position();
|
||||
_update_tool_erase();
|
||||
_update_edited_point_pos();
|
||||
_update_edited_point_name();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If no point was selected, select host BlendSpace1D node.
|
||||
if (selected_point == -1) {
|
||||
EditorNode::get_singleton()->push_item(blend_space.ptr(), "", true);
|
||||
}
|
||||
}
|
||||
|
||||
if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) {
|
||||
// Check if releasing over text without any dragging - if so, start text editing instead.
|
||||
if (!read_only && !dragging_selected) {
|
||||
for (int i = 0; i < text_rects.size(); i++) {
|
||||
if (text_rects[i].has_point(mb->get_position())) {
|
||||
_start_inline_edit(i);
|
||||
dragging_selected_attempt = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!read_only) {
|
||||
if (dragging_selected) {
|
||||
// move
|
||||
|
|
@ -170,7 +194,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
|
||||
updating = true;
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Move Node Point"));
|
||||
undo_redo->create_action(TTR("Move BlendSpace1D Node Point"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
|
|
@ -221,6 +245,28 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
// Handle mousewheel for reordering points.
|
||||
Ref<InputEventMouseButton> mw = p_event;
|
||||
if (mw.is_valid() && mw->is_pressed() && (mw->get_button_index() == MouseButton::WHEEL_UP || mw->get_button_index() == MouseButton::WHEEL_DOWN)) {
|
||||
if (!read_only && tool_select->is_pressed()) {
|
||||
int hovered_point = -1;
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
if (Math::abs(float(points[i] - mw->get_position().x)) < 10 * EDSCALE) {
|
||||
hovered_point = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hovered_point != -1) {
|
||||
int direction = (mw->get_button_index() == MouseButton::WHEEL_DOWN) ? -1 : 1;
|
||||
int new_index = hovered_point + direction;
|
||||
_set_selected_point(hovered_point);
|
||||
_edit_point_index(new_index);
|
||||
accept_event();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
|
||||
|
|
@ -229,6 +275,9 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Clear text rectangles for fresh click detection.
|
||||
text_rects.clear();
|
||||
|
||||
Color linecolor = get_theme_color(SceneStringName(font_color), SNAME("Label"));
|
||||
Color linecolor_soft = linecolor;
|
||||
linecolor_soft.a *= 0.5;
|
||||
|
|
@ -282,31 +331,33 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() {
|
|||
|
||||
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
|
||||
float point = blend_space->get_blend_point_position(i);
|
||||
|
||||
if (!read_only) {
|
||||
if (dragging_selected && selected_point == i) {
|
||||
point += drag_ofs.x;
|
||||
if (snap->is_pressed()) {
|
||||
point = Math::snapped(point, blend_space->get_snap());
|
||||
}
|
||||
if (!read_only && dragging_selected && selected_point == i) {
|
||||
point += drag_ofs.x;
|
||||
if (snap->is_pressed()) {
|
||||
point = Math::snapped(point, blend_space->get_snap());
|
||||
}
|
||||
}
|
||||
|
||||
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
|
||||
point *= s.width;
|
||||
|
||||
points.push_back(point);
|
||||
|
||||
Vector2 gui_point = Vector2(point, s.height / 2.0);
|
||||
Vector2 gui_point = (Vector2(point, s.height / 2.0) - icon->get_size() / 2.0).floor();
|
||||
blend_space_draw->draw_texture(i == selected_point ? icon_selected : icon, gui_point);
|
||||
|
||||
gui_point -= (icon->get_size() / 2.0);
|
||||
if (point >= 0.0 && point <= s.width && editing_point != i) {
|
||||
String name_text = show_indices ? itos(i) : String(blend_space->get_blend_point_name(i));
|
||||
Vector2 text_size = font->get_string_size(name_text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
|
||||
Vector2 text_pos = Vector2(CLAMP(point - text_size.x / 2.0, 0, s.width - text_size.x), gui_point.y - 4 * EDSCALE);
|
||||
|
||||
gui_point = gui_point.floor();
|
||||
Color name_color = i == selected_point ? get_theme_color(SNAME("accent_color"), EditorStringName(Editor)) : linecolor;
|
||||
blend_space_draw->draw_string(font, text_pos, name_text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, name_color);
|
||||
|
||||
if (i == selected_point) {
|
||||
blend_space_draw->draw_texture(icon_selected, gui_point);
|
||||
} else {
|
||||
blend_space_draw->draw_texture(icon, gui_point);
|
||||
if (text_rects.size() <= i) {
|
||||
text_rects.resize(i + 1);
|
||||
}
|
||||
|
||||
text_rects.write[i] = Rect2(Vector2(text_pos.x, text_pos.y - font->get_ascent(font_size)), text_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -413,6 +464,19 @@ void AnimationNodeBlendSpace1DEditor::_file_opened(const String &p_file) {
|
|||
}
|
||||
}
|
||||
|
||||
String AnimationNodeBlendSpace1DEditor::_get_safe_name(const Ref<AnimationNodeBlendSpace1D> &p_blend_space, const String &p_name) {
|
||||
String final_name = p_name;
|
||||
|
||||
// Append a number suffix if there's a naming conflict.
|
||||
int suffix = 1;
|
||||
while (p_blend_space->find_blend_point_by_name(final_name) != -1) {
|
||||
suffix++;
|
||||
final_name = p_name + " " + itos(suffix);
|
||||
}
|
||||
|
||||
return final_name;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
|
||||
Ref<AnimationRootNode> node;
|
||||
if (p_index == MENU_LOAD_FILE) {
|
||||
|
|
@ -448,7 +512,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
|
|||
updating = true;
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Add Node Point"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos);
|
||||
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos, -1, _get_safe_name(blend_space, node->get_class().replace_first("AnimationNode", "")));
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
undo_redo->add_undo_method(this, "_update_space");
|
||||
|
|
@ -467,7 +531,7 @@ void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) {
|
|||
updating = true;
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Add Animation Point"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos);
|
||||
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos, -1, _get_safe_name(blend_space, animations_to_add[p_index]));
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
undo_redo->add_undo_method(this, "_update_space");
|
||||
|
|
@ -508,10 +572,19 @@ void AnimationNodeBlendSpace1DEditor::_update_edited_point_pos() {
|
|||
|
||||
updating = true;
|
||||
edit_value->set_value(pos);
|
||||
index_edit->set_max(blend_space->get_blend_point_count() - 1);
|
||||
index_edit->set_value(selected_point);
|
||||
index_edit->set_editable(blend_space->get_blend_point_count() > 1 && !read_only);
|
||||
updating = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_update_edited_point_name() {
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
|
||||
bool point_valid = selected_point >= 0 && selected_point < blend_space->get_blend_point_count();
|
||||
tool_erase->set_disabled(!point_valid || read_only);
|
||||
|
|
@ -521,8 +594,10 @@ void AnimationNodeBlendSpace1DEditor::_update_tool_erase() {
|
|||
|
||||
if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
|
||||
open_editor->show();
|
||||
open_editor_sep->show();
|
||||
} else {
|
||||
open_editor->hide();
|
||||
open_editor_sep->hide();
|
||||
}
|
||||
|
||||
if (!read_only) {
|
||||
|
|
@ -539,19 +614,21 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() {
|
|||
if (selected_point != -1) {
|
||||
updating = true;
|
||||
|
||||
Ref<AnimationRootNode> node = blend_space->get_blend_point_node(selected_point);
|
||||
float position = blend_space->get_blend_point_position(selected_point);
|
||||
String point_name = blend_space->get_blend_point_name(selected_point);
|
||||
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Remove BlendSpace1D Point"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point);
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", blend_space->get_blend_point_node(selected_point), blend_space->get_blend_point_position(selected_point), selected_point);
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", node, position, selected_point, point_name);
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
undo_redo->add_undo_method(this, "_update_space");
|
||||
undo_redo->commit_action();
|
||||
|
||||
// Return selection to host BlendSpace1D node.
|
||||
EditorNode::get_singleton()->push_item(blend_space.ptr(), "", true);
|
||||
_set_selected_point(-1);
|
||||
|
||||
updating = false;
|
||||
_update_tool_erase();
|
||||
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
|
@ -577,11 +654,77 @@ void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) {
|
|||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_edit_point_index(double p_index) {
|
||||
if (updating || selected_point < 0 || selected_point >= blend_space->get_blend_point_count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int new_index = (int)p_index;
|
||||
if (new_index < 0 || new_index >= blend_space->get_blend_point_count() || new_index == selected_point) {
|
||||
return;
|
||||
}
|
||||
|
||||
updating = true;
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Reorder BlendSpace1D Point Index"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "reorder_blend_point", selected_point, new_index);
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "reorder_blend_point", new_index, selected_point);
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
undo_redo->add_undo_method(this, "_update_space");
|
||||
undo_redo->add_do_method(this, "_set_selected_point", new_index);
|
||||
undo_redo->add_undo_method(this, "_set_selected_point", selected_point);
|
||||
undo_redo->add_do_method(this, "_show_indices_with_cooldown");
|
||||
undo_redo->add_undo_method(this, "_show_indices_with_cooldown");
|
||||
undo_redo->commit_action();
|
||||
updating = false;
|
||||
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_set_selected_point(int p_index) {
|
||||
selected_point = p_index;
|
||||
_update_tool_erase();
|
||||
if (p_index != -1) {
|
||||
_update_edited_point_pos();
|
||||
Ref<AnimationNode> node = blend_space->get_blend_point_node(p_index);
|
||||
EditorNode::get_singleton()->push_item(node.ptr(), "", true);
|
||||
} else {
|
||||
// Return selection to host BlendSpace1D node.
|
||||
EditorNode::get_singleton()->push_item(blend_space.ptr(), "", true);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_edit_point_name(const String &p_name) {
|
||||
if (updating || selected_point == -1 || p_name.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String old_name = blend_space->get_blend_point_name(selected_point);
|
||||
if (p_name == old_name) {
|
||||
return;
|
||||
}
|
||||
String safe_name = _get_safe_name(blend_space, p_name);
|
||||
|
||||
updating = true;
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Change BlendSpace1D Point Name"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_name", selected_point, safe_name);
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_name", selected_point, old_name);
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
undo_redo->add_undo_method(this, "_update_space");
|
||||
undo_redo->add_do_method(this, "_update_edited_point_name");
|
||||
undo_redo->add_undo_method(this, "_update_edited_point_name");
|
||||
undo_redo->commit_action();
|
||||
updating = false;
|
||||
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_open_editor() {
|
||||
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
|
||||
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
|
||||
ERR_FAIL_COND(an.is_null());
|
||||
AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point));
|
||||
AnimationTreeEditor::get_singleton()->enter_editor(blend_space->get_blend_point_name(selected_point));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -634,6 +777,9 @@ void AnimationNodeBlendSpace1DEditor::_bind_methods() {
|
|||
ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace1DEditor::_update_tool_erase);
|
||||
|
||||
ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace1DEditor::_update_edited_point_pos);
|
||||
ClassDB::bind_method("_update_edited_point_name", &AnimationNodeBlendSpace1DEditor::_update_edited_point_name);
|
||||
ClassDB::bind_method("_set_selected_point", &AnimationNodeBlendSpace1DEditor::_set_selected_point);
|
||||
ClassDB::bind_method("_show_indices_with_cooldown", &AnimationNodeBlendSpace1DEditor::_show_indices_with_cooldown);
|
||||
}
|
||||
|
||||
bool AnimationNodeBlendSpace1DEditor::can_edit(const Ref<AnimationNode> &p_node) {
|
||||
|
|
@ -653,6 +799,7 @@ void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
|
|||
|
||||
tool_create->set_disabled(read_only);
|
||||
edit_value->set_editable(!read_only);
|
||||
index_edit->set_editable(!read_only);
|
||||
label_value->set_editable(!read_only);
|
||||
min_value->set_editable(!read_only);
|
||||
max_value->set_editable(!read_only);
|
||||
|
|
@ -660,6 +807,133 @@ void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
|
|||
interpolation->set_disabled(read_only);
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_start_inline_edit(int p_point) {
|
||||
if (editing_point != -1 || p_point < 0 || p_point >= blend_space->get_blend_point_count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
editing_point = p_point;
|
||||
_set_selected_point(p_point);
|
||||
|
||||
inline_editor = memnew(LineEdit);
|
||||
blend_space_draw->add_child(inline_editor);
|
||||
|
||||
inline_editor->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("accent_color"), EditorStringName(Editor)));
|
||||
inline_editor->add_theme_color_override("font_selected_color", Color::named("white"));
|
||||
inline_editor->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), EditorStringName(Editor)));
|
||||
StyleBoxEmpty *empty_style = memnew(StyleBoxEmpty);
|
||||
empty_style->set_content_margin_all(0);
|
||||
inline_editor->add_theme_style_override(CoreStringName(normal), empty_style);
|
||||
inline_editor->add_theme_style_override("focus", memnew(StyleBoxEmpty));
|
||||
inline_editor->add_theme_style_override("read_only", memnew(StyleBoxEmpty));
|
||||
inline_editor->add_theme_constant_override("minimum_character_width", 0);
|
||||
inline_editor->set_flat(true);
|
||||
|
||||
inline_editor->set_text(blend_space->get_blend_point_name(p_point));
|
||||
inline_editor->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
|
||||
inline_editor->set_expand_to_text_length_enabled(true);
|
||||
|
||||
if (p_point < text_rects.size() && p_point < points.size()) {
|
||||
Rect2 text_rect = text_rects[p_point];
|
||||
|
||||
inline_editor_point_x = points[p_point];
|
||||
|
||||
float editor_width = text_rect.size.x;
|
||||
inline_editor->set_size(Vector2(editor_width, text_rect.size.y));
|
||||
|
||||
Size2 s = blend_space_draw->get_size();
|
||||
|
||||
float editor_x = inline_editor_point_x - editor_width / 2.0;
|
||||
editor_x = CLAMP(editor_x, 0.0f, s.width - editor_width);
|
||||
inline_editor->set_position(Vector2(editor_x, text_rect.position.y - 1 * EDSCALE));
|
||||
}
|
||||
|
||||
inline_editor->connect(SceneStringName(text_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_inline_editor_text_changed));
|
||||
inline_editor->connect(SceneStringName(text_submitted), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_finish_inline_edit_with_text));
|
||||
inline_editor->connect(SceneStringName(focus_exited), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_finish_inline_edit));
|
||||
|
||||
inline_editor->grab_focus();
|
||||
inline_editor->select_all();
|
||||
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_finish_inline_edit() {
|
||||
if (editing_point == -1 || !inline_editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
String new_name = inline_editor->get_text();
|
||||
_edit_point_name(new_name);
|
||||
|
||||
_cancel_inline_edit();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_finish_inline_edit_with_text(const String &p_text) {
|
||||
if (editing_point == -1 || !inline_editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
_edit_point_name(p_text);
|
||||
|
||||
_cancel_inline_edit();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_cancel_inline_edit() {
|
||||
if (inline_editor) {
|
||||
inline_editor->queue_free();
|
||||
inline_editor = nullptr;
|
||||
}
|
||||
editing_point = -1;
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_inline_editor_text_changed(const String &p_text) {
|
||||
if (!inline_editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
inline_editor->set_size(Vector2(0, inline_editor->get_size().y));
|
||||
|
||||
Vector2 editor_size = inline_editor->get_size();
|
||||
Size2 s = blend_space_draw->get_size();
|
||||
|
||||
float editor_x = inline_editor_point_x - editor_size.x / 2.0;
|
||||
editor_x = CLAMP(editor_x, 0.0f, s.width - editor_size.x);
|
||||
|
||||
inline_editor->set_position(Vector2(editor_x, inline_editor->get_position().y));
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_index_edit_focus_entered() {
|
||||
if (index_focus_cooldown_timer->is_stopped() == false) {
|
||||
index_focus_cooldown_timer->stop();
|
||||
}
|
||||
index_edit_has_focus = true;
|
||||
show_indices = true;
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_index_edit_focus_exited() {
|
||||
index_edit_has_focus = false;
|
||||
index_focus_cooldown_timer->start();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_index_focus_cooldown_timeout() {
|
||||
if (!index_edit_has_focus) {
|
||||
show_indices = false;
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1DEditor::_show_indices_with_cooldown() {
|
||||
if (index_focus_cooldown_timer->is_stopped() == false) {
|
||||
index_focus_cooldown_timer->stop();
|
||||
}
|
||||
show_indices = true;
|
||||
index_focus_cooldown_timer->start();
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr;
|
||||
|
||||
AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
|
||||
|
|
@ -677,7 +951,7 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
|
|||
tool_select->set_button_group(bg);
|
||||
top_hb->add_child(tool_select);
|
||||
tool_select->set_pressed(true);
|
||||
tool_select->set_tooltip_text(TTR("Select and move points.\nRMB: Create point at position clicked.\nShift+LMB+Drag: Set the blending position within the space."));
|
||||
tool_select->set_tooltip_text(TTR("Select and move points.\nRMB: Create point at position clicked.\nShift+LMB+Drag: Set the blending position within the space.\nScroll: Increment or decrement index."));
|
||||
tool_select->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_tool_switch).bind(0));
|
||||
|
||||
tool_create = memnew(Button);
|
||||
|
|
@ -722,23 +996,46 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
|
|||
snap_value->set_accessibility_name(TTRC("Grid Step"));
|
||||
|
||||
top_hb->add_child(memnew(VSeparator));
|
||||
top_hb->add_child(memnew(Label(TTR("Sync:"))));
|
||||
top_hb->add_child(memnew(Label(TTR("Sync"))));
|
||||
sync = memnew(CheckBox);
|
||||
top_hb->add_child(sync);
|
||||
sync->connect(SceneStringName(toggled), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
|
||||
|
||||
top_hb->add_child(memnew(VSeparator));
|
||||
|
||||
top_hb->add_child(memnew(Label(TTR("Blend:"))));
|
||||
top_hb->add_child(memnew(Label(TTR("Blend"))));
|
||||
interpolation = memnew(OptionButton);
|
||||
top_hb->add_child(interpolation);
|
||||
interpolation->connect(SceneStringName(item_selected), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
|
||||
|
||||
top_hb->add_spacer();
|
||||
|
||||
edit_hb = memnew(HBoxContainer);
|
||||
top_hb->add_child(edit_hb);
|
||||
edit_hb->add_child(memnew(VSeparator));
|
||||
edit_hb->add_child(memnew(Label(TTR("Point"))));
|
||||
|
||||
open_editor = memnew(Button);
|
||||
edit_hb->add_child(open_editor);
|
||||
open_editor->set_text(TTR("Open Editor"));
|
||||
open_editor->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_open_editor), CONNECT_DEFERRED);
|
||||
open_editor_sep = memnew(VSeparator);
|
||||
edit_hb->add_child(open_editor_sep);
|
||||
|
||||
edit_hb->add_child(memnew(Label(TTR("Index"))));
|
||||
index_edit = memnew(SpinBox);
|
||||
edit_hb->add_child(index_edit);
|
||||
index_edit->set_min(0);
|
||||
index_edit->set_step(1);
|
||||
index_edit->set_allow_greater(false);
|
||||
index_edit->set_allow_lesser(false);
|
||||
index_edit->set_accessibility_name(TTRC("Blend Point Index"));
|
||||
index_edit->set_tooltip_text(TTR("Index of the blend point.\nValues outside of the valid range will be clamped to the nearest index."));
|
||||
index_edit->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_edit_point_index));
|
||||
index_edit->get_line_edit()->connect(SceneStringName(focus_entered), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_index_edit_focus_entered));
|
||||
index_edit->get_line_edit()->connect(SceneStringName(focus_exited), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_index_edit_focus_exited));
|
||||
|
||||
edit_hb->add_child(memnew(VSeparator));
|
||||
|
||||
edit_hb->add_child(memnew(Label(TTR("Position"))));
|
||||
edit_value = memnew(SpinBox);
|
||||
edit_hb->add_child(edit_value);
|
||||
edit_value->set_min(-1000);
|
||||
|
|
@ -747,13 +1044,9 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
|
|||
edit_value->set_accessibility_name(TTRC("Blend Value"));
|
||||
edit_value->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_edit_point_pos));
|
||||
|
||||
open_editor = memnew(Button);
|
||||
edit_hb->add_child(open_editor);
|
||||
open_editor->set_text(TTR("Open Editor"));
|
||||
open_editor->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace1DEditor::_open_editor), CONNECT_DEFERRED);
|
||||
|
||||
edit_hb->hide();
|
||||
open_editor->hide();
|
||||
open_editor_sep->hide();
|
||||
|
||||
VBoxContainer *main_vb = memnew(VBoxContainer);
|
||||
add_child(main_vb);
|
||||
|
|
@ -830,5 +1123,12 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
|
|||
open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
|
||||
open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_file_opened));
|
||||
|
||||
// Create timer for index focus cooldown (1.5 seconds).
|
||||
index_focus_cooldown_timer = memnew(Timer);
|
||||
add_child(index_focus_cooldown_timer);
|
||||
index_focus_cooldown_timer->set_wait_time(1.5);
|
||||
index_focus_cooldown_timer->set_one_shot(true);
|
||||
index_focus_cooldown_timer->connect("timeout", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_index_focus_cooldown_timeout));
|
||||
|
||||
set_custom_minimum_size(Size2(0, 150 * EDSCALE));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class LineEdit;
|
|||
class OptionButton;
|
||||
class PanelContainer;
|
||||
class SpinBox;
|
||||
class Timer;
|
||||
class VSeparator;
|
||||
|
||||
class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
|
||||
|
|
@ -68,6 +69,8 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
|
|||
HBoxContainer *edit_hb = nullptr;
|
||||
SpinBox *edit_value = nullptr;
|
||||
Button *open_editor = nullptr;
|
||||
VSeparator *open_editor_sep = nullptr;
|
||||
SpinBox *index_edit = nullptr;
|
||||
|
||||
int selected_point = -1;
|
||||
|
||||
|
|
@ -101,15 +104,36 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
|
|||
Vector2 drag_from;
|
||||
Vector2 drag_ofs;
|
||||
|
||||
Vector<Rect2> text_rects;
|
||||
int editing_point = -1;
|
||||
LineEdit *inline_editor = nullptr;
|
||||
float inline_editor_point_x = 0.0f;
|
||||
bool index_edit_has_focus = false;
|
||||
bool show_indices = false;
|
||||
Timer *index_focus_cooldown_timer = nullptr;
|
||||
|
||||
void _add_menu_type(int p_index);
|
||||
void _add_animation_type(int p_index);
|
||||
|
||||
void _tool_switch(int p_tool);
|
||||
void _update_edited_point_pos();
|
||||
void _update_edited_point_name();
|
||||
void _update_tool_erase();
|
||||
void _erase_selected();
|
||||
void _edit_point_pos(double);
|
||||
void _edit_point_name(const String &p_name);
|
||||
void _edit_point_index(double p_index);
|
||||
void _set_selected_point(int p_index);
|
||||
void _start_inline_edit(int p_point);
|
||||
void _finish_inline_edit();
|
||||
void _finish_inline_edit_with_text(const String &p_text);
|
||||
void _cancel_inline_edit();
|
||||
void _inline_editor_text_changed(const String &p_text);
|
||||
void _open_editor();
|
||||
void _index_edit_focus_entered();
|
||||
void _index_edit_focus_exited();
|
||||
void _index_focus_cooldown_timeout();
|
||||
void _show_indices_with_cooldown();
|
||||
|
||||
EditorFileDialog *open_file = nullptr;
|
||||
Ref<AnimationNode> file_loaded;
|
||||
|
|
@ -122,6 +146,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
|
|||
};
|
||||
|
||||
StringName get_blend_position_path() const;
|
||||
String _get_safe_name(const Ref<AnimationNodeBlendSpace1D> &p_blend_space, const String &p_name);
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
|
@ -129,6 +154,7 @@ protected:
|
|||
|
||||
public:
|
||||
static AnimationNodeBlendSpace1DEditor *get_singleton() { return singleton; }
|
||||
void refresh_editor() { _update_space(); }
|
||||
virtual bool can_edit(const Ref<AnimationNode> &p_node) override;
|
||||
virtual void edit(const Ref<AnimationNode> &p_node) override;
|
||||
AnimationNodeBlendSpace1DEditor();
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
#include "scene/gui/panel_container.h"
|
||||
#include "scene/gui/separator.h"
|
||||
#include "scene/gui/spin_box.h"
|
||||
#include "scene/main/timer.h"
|
||||
#include "scene/main/window.h"
|
||||
|
||||
bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node) {
|
||||
|
|
@ -86,6 +87,7 @@ void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) {
|
|||
label_y->set_editable(!read_only);
|
||||
edit_x->set_editable(!read_only);
|
||||
edit_y->set_editable(!read_only);
|
||||
index_edit->set_editable(!read_only);
|
||||
tool_triangle->set_disabled(read_only);
|
||||
auto_triangles->set_disabled(read_only);
|
||||
sync->set_disabled(read_only);
|
||||
|
|
@ -104,12 +106,20 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
}
|
||||
|
||||
Ref<InputEventKey> k = p_event;
|
||||
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) {
|
||||
if (selected_point != -1 || selected_triangle != -1) {
|
||||
if (!read_only) {
|
||||
_erase_selected();
|
||||
}
|
||||
if (k.is_valid() && k->is_pressed() && !k->is_echo()) {
|
||||
if (k->get_keycode() == Key::ESCAPE && editing_point != -1) {
|
||||
_cancel_inline_edit();
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
|
||||
if (tool_select->is_pressed() && k->get_keycode() == Key::KEY_DELETE) {
|
||||
if (selected_point != -1 || selected_triangle != -1) {
|
||||
if (!read_only) {
|
||||
_erase_selected();
|
||||
}
|
||||
accept_event();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,17 +178,28 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
|
||||
if (mb.is_valid() && mb->is_pressed() && tool_select->is_pressed() && !mb->is_shift_pressed() && !mb->is_command_or_control_pressed() && mb->get_button_index() == MouseButton::LEFT) {
|
||||
blend_space_draw->queue_redraw(); //update anyway
|
||||
//try to see if a point can be selected
|
||||
selected_point = -1;
|
||||
selected_triangle = -1;
|
||||
_update_tool_erase();
|
||||
|
||||
//try to see if a point can be selected
|
||||
_set_selected_point(-1);
|
||||
selected_triangle = -1;
|
||||
|
||||
// Check if clicking on text areas first.
|
||||
for (int i = 0; i < text_rects.size(); i++) {
|
||||
if (text_rects[i].has_point(mb->get_position())) {
|
||||
_set_selected_point(i);
|
||||
dragging_selected_attempt = true;
|
||||
drag_from = mb->get_position();
|
||||
_update_edited_point_name();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Then check point positions.
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
if (points[i].distance_to(mb->get_position()) < 10 * EDSCALE) {
|
||||
selected_point = i;
|
||||
Ref<AnimationNode> node = blend_space->get_blend_point_node(i);
|
||||
EditorNode::get_singleton()->push_item(node.ptr(), "", true);
|
||||
_set_selected_point(i);
|
||||
|
||||
Ref<AnimationNode> node = blend_space->get_blend_point_node(i);
|
||||
if (mb->is_double_click() && AnimationTreeEditor::get_singleton()->can_edit(node)) {
|
||||
_open_editor();
|
||||
return;
|
||||
|
|
@ -186,8 +207,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
|
||||
dragging_selected_attempt = true;
|
||||
drag_from = mb->get_position();
|
||||
_update_tool_erase();
|
||||
_update_edited_point_pos();
|
||||
_update_edited_point_name();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -210,17 +230,12 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no point or triangle was selected, select host BlendSpace2D node.
|
||||
if (selected_point == -1 && selected_triangle == -1) {
|
||||
EditorNode::get_singleton()->push_item(blend_space.ptr(), "", true);
|
||||
}
|
||||
}
|
||||
|
||||
if (mb.is_valid() && mb->is_pressed() && tool_triangle->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
|
||||
blend_space_draw->queue_redraw(); //update anyway
|
||||
//try to see if a point can be selected
|
||||
selected_point = -1;
|
||||
_set_selected_point(-1);
|
||||
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
if (making_triangle.has(i)) {
|
||||
|
|
@ -254,6 +269,17 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
}
|
||||
|
||||
if (mb.is_valid() && !mb->is_pressed() && dragging_selected_attempt && mb->get_button_index() == MouseButton::LEFT) {
|
||||
// Check if releasing over text without actual dragging - if so, start text editing instead.
|
||||
if (!read_only && !dragging_selected) {
|
||||
for (int i = 0; i < text_rects.size(); i++) {
|
||||
if (text_rects[i].has_point(mb->get_position())) {
|
||||
_start_inline_edit(i);
|
||||
dragging_selected_attempt = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dragging_selected) {
|
||||
//move
|
||||
Vector2 point = blend_space->get_blend_point_position(selected_point);
|
||||
|
|
@ -265,7 +291,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
if (!read_only) {
|
||||
updating = true;
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Move Node Point"));
|
||||
undo_redo->create_action(TTR("Move BlendSpace2D Node Point"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
|
|
@ -327,6 +353,29 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
|
|||
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
// Handle mousewheel for reordering points.
|
||||
Ref<InputEventMouseButton> mw = p_event;
|
||||
if (mw.is_valid() && mw->is_pressed() && (mw->get_button_index() == MouseButton::WHEEL_UP || mw->get_button_index() == MouseButton::WHEEL_DOWN)) {
|
||||
if (!read_only && tool_select->is_pressed()) {
|
||||
// Check if hovering over a point.
|
||||
int hovered_point = -1;
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
if (points[i].distance_to(mw->get_position()) < 10 * EDSCALE) {
|
||||
hovered_point = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hovered_point != -1) {
|
||||
int direction = (mw->get_button_index() == MouseButton::WHEEL_DOWN) ? -1 : 1;
|
||||
int new_index = hovered_point + direction;
|
||||
_set_selected_point(hovered_point);
|
||||
_edit_point_index(new_index);
|
||||
accept_event();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_file_opened(const String &p_file) {
|
||||
|
|
@ -338,6 +387,19 @@ void AnimationNodeBlendSpace2DEditor::_file_opened(const String &p_file) {
|
|||
}
|
||||
}
|
||||
|
||||
String AnimationNodeBlendSpace2DEditor::_get_safe_name(const Ref<AnimationNodeBlendSpace2D> &p_blend_space, const String &p_name) {
|
||||
String final_name = p_name;
|
||||
|
||||
// Append a number suffix if there's a naming conflict.
|
||||
int suffix = 1;
|
||||
while (p_blend_space->find_blend_point_by_name(final_name) != -1) {
|
||||
suffix++;
|
||||
final_name = p_name + " " + itos(suffix);
|
||||
}
|
||||
|
||||
return final_name;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
|
||||
Ref<AnimationRootNode> node;
|
||||
if (p_index == MENU_LOAD_FILE) {
|
||||
|
|
@ -373,7 +435,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
|
|||
updating = true;
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Add Node Point"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos);
|
||||
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos, -1, _get_safe_name(blend_space, node->get_class().replace_first("AnimationNode", "")));
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
undo_redo->add_undo_method(this, "_update_space");
|
||||
|
|
@ -392,7 +454,7 @@ void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
|
|||
updating = true;
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Add Animation Point"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos);
|
||||
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos, -1, _get_safe_name(blend_space, animations_to_add[p_index]));
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
undo_redo->add_undo_method(this, "_update_space");
|
||||
|
|
@ -411,8 +473,10 @@ void AnimationNodeBlendSpace2DEditor::_update_tool_erase() {
|
|||
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
|
||||
if (AnimationTreeEditor::get_singleton()->can_edit(an)) {
|
||||
open_editor->show();
|
||||
open_editor_sep->show();
|
||||
} else {
|
||||
open_editor->hide();
|
||||
open_editor_sep->hide();
|
||||
}
|
||||
if (!read_only) {
|
||||
edit_hb->show();
|
||||
|
|
@ -455,6 +519,9 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Clear text rectangles for fresh click detection.
|
||||
text_rects.clear();
|
||||
|
||||
Color linecolor = get_theme_color(SceneStringName(font_color), SNAME("Label"));
|
||||
Color linecolor_soft = linecolor;
|
||||
linecolor_soft.a *= 0.5;
|
||||
|
|
@ -563,26 +630,39 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() {
|
|||
points.clear();
|
||||
for (int i = 0; i < blend_space->get_blend_point_count(); i++) {
|
||||
Vector2 point = blend_space->get_blend_point_position(i);
|
||||
if (!read_only) {
|
||||
if (dragging_selected && selected_point == i) {
|
||||
point += drag_ofs;
|
||||
if (snap->is_pressed()) {
|
||||
point = point.snapped(blend_space->get_snap());
|
||||
}
|
||||
if (!read_only && dragging_selected && selected_point == i) {
|
||||
point += drag_ofs;
|
||||
if (snap->is_pressed()) {
|
||||
point = point.snapped(blend_space->get_snap());
|
||||
}
|
||||
}
|
||||
|
||||
point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space());
|
||||
point *= s;
|
||||
point.y = s.height - point.y;
|
||||
|
||||
points.push_back(point);
|
||||
point -= (icon->get_size() / 2);
|
||||
point = point.floor();
|
||||
|
||||
if (i == selected_point) {
|
||||
blend_space_draw->draw_texture(icon_selected, point);
|
||||
} else {
|
||||
blend_space_draw->draw_texture(icon, point);
|
||||
Vector2 gui_point = (point - icon->get_size() / 2).floor();
|
||||
blend_space_draw->draw_texture(i == selected_point ? icon_selected : icon, gui_point);
|
||||
|
||||
if (point.x >= 0.0 && point.x <= s.width && point.y >= 0.0 && point.y <= s.height && editing_point != i) {
|
||||
String name_text = show_indices ? itos(i) : String(blend_space->get_blend_point_name(i));
|
||||
Vector2 text_size = font->get_string_size(name_text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size);
|
||||
|
||||
float half_icon_h = icon->get_size().y / 2.0;
|
||||
float above_pos_y = point.y - half_icon_h - 4 * EDSCALE;
|
||||
float text_x = CLAMP(point.x - text_size.x / 2.0, 0, s.width - text_size.x);
|
||||
float text_y = above_pos_y >= text_size.y ? above_pos_y : point.y + half_icon_h + font->get_ascent(font_size);
|
||||
Vector2 text_pos = Vector2(text_x, text_y);
|
||||
|
||||
Color name_color = i == selected_point ? get_theme_color(SNAME("accent_color"), EditorStringName(Editor)) : linecolor;
|
||||
blend_space_draw->draw_string(font, text_pos, name_text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, name_color);
|
||||
|
||||
if (text_rects.size() <= i) {
|
||||
text_rects.resize(i + 1);
|
||||
}
|
||||
|
||||
text_rects.write[i] = Rect2(Vector2(text_pos.x, text_pos.y - font->get_ascent(font_size)), text_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -727,9 +807,14 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() {
|
|||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
if (selected_point != -1) {
|
||||
updating = true;
|
||||
|
||||
Ref<AnimationRootNode> node = blend_space->get_blend_point_node(selected_point);
|
||||
Vector2 position = blend_space->get_blend_point_position(selected_point);
|
||||
String point_name = blend_space->get_blend_point_name(selected_point);
|
||||
|
||||
undo_redo->create_action(TTR("Remove BlendSpace2D Point"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point);
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", blend_space->get_blend_point_node(selected_point), blend_space->get_blend_point_position(selected_point), selected_point);
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", node, position, selected_point, point_name);
|
||||
|
||||
//restore triangles using this point
|
||||
for (int i = 0; i < blend_space->get_triangle_count(); i++) {
|
||||
|
|
@ -745,11 +830,9 @@ void AnimationNodeBlendSpace2DEditor::_erase_selected() {
|
|||
undo_redo->add_undo_method(this, "_update_space");
|
||||
undo_redo->commit_action();
|
||||
|
||||
// Return selection to host BlendSpace2D node.
|
||||
EditorNode::get_singleton()->push_item(blend_space.ptr(), "", true);
|
||||
_set_selected_point(-1);
|
||||
|
||||
updating = false;
|
||||
_update_tool_erase();
|
||||
|
||||
blend_space_draw->queue_redraw();
|
||||
} else if (selected_triangle != -1) {
|
||||
|
|
@ -787,17 +870,26 @@ void AnimationNodeBlendSpace2DEditor::_update_edited_point_pos() {
|
|||
updating = true;
|
||||
edit_x->set_value(pos.x);
|
||||
edit_y->set_value(pos.y);
|
||||
index_edit->set_max(blend_space->get_blend_point_count() - 1);
|
||||
index_edit->set_value(selected_point);
|
||||
index_edit->set_editable(blend_space->get_blend_point_count() > 1 && !read_only);
|
||||
updating = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_update_edited_point_name() {
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) {
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
updating = true;
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Move Node Point"));
|
||||
undo_redo->create_action(TTR("Move BlendSpace2D Node Point"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, Vector2(edit_x->get_value(), edit_y->get_value()));
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
|
|
@ -810,6 +902,71 @@ void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) {
|
|||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_edit_point_index(double p_index) {
|
||||
if (updating || selected_point < 0 || selected_point >= blend_space->get_blend_point_count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int new_index = (int)p_index;
|
||||
if (new_index < 0 || new_index >= blend_space->get_blend_point_count() || new_index == selected_point) {
|
||||
return;
|
||||
}
|
||||
|
||||
updating = true;
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Reorder BlendSpace2D Point Index"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "reorder_blend_point", selected_point, new_index);
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "reorder_blend_point", new_index, selected_point);
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
undo_redo->add_undo_method(this, "_update_space");
|
||||
undo_redo->add_do_method(this, "_set_selected_point", new_index);
|
||||
undo_redo->add_undo_method(this, "_set_selected_point", selected_point);
|
||||
undo_redo->add_do_method(this, "_show_indices_with_cooldown");
|
||||
undo_redo->add_undo_method(this, "_show_indices_with_cooldown");
|
||||
undo_redo->commit_action();
|
||||
updating = false;
|
||||
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_set_selected_point(int p_index) {
|
||||
selected_point = p_index;
|
||||
_update_tool_erase();
|
||||
if (p_index != -1) {
|
||||
_update_edited_point_pos();
|
||||
Ref<AnimationNode> node = blend_space->get_blend_point_node(p_index);
|
||||
EditorNode::get_singleton()->push_item(node.ptr(), "", true);
|
||||
} else {
|
||||
EditorNode::get_singleton()->push_item(blend_space.ptr(), "", true);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_edit_point_name(const String &p_name) {
|
||||
if (updating || selected_point == -1 || p_name.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String old_name = blend_space->get_blend_point_name(selected_point);
|
||||
if (p_name == old_name) {
|
||||
return;
|
||||
}
|
||||
String safe_name = _get_safe_name(blend_space, p_name);
|
||||
|
||||
updating = true;
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Change BlendSpace2D Point Name"));
|
||||
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_name", selected_point, safe_name);
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_name", selected_point, old_name);
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
undo_redo->add_undo_method(this, "_update_space");
|
||||
undo_redo->add_do_method(this, "_update_edited_point_name");
|
||||
undo_redo->add_undo_method(this, "_update_edited_point_name");
|
||||
undo_redo->commit_action();
|
||||
updating = false;
|
||||
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_THEME_CHANGED: {
|
||||
|
|
@ -864,10 +1021,40 @@ void AnimationNodeBlendSpace2DEditor::_open_editor() {
|
|||
if (selected_point >= 0 && selected_point < blend_space->get_blend_point_count()) {
|
||||
Ref<AnimationNode> an = blend_space->get_blend_point_node(selected_point);
|
||||
ERR_FAIL_COND(an.is_null());
|
||||
AnimationTreeEditor::get_singleton()->enter_editor(itos(selected_point));
|
||||
AnimationTreeEditor::get_singleton()->enter_editor(blend_space->get_blend_point_name(selected_point));
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_index_edit_focus_entered() {
|
||||
if (index_focus_cooldown_timer->is_stopped() == false) {
|
||||
index_focus_cooldown_timer->stop();
|
||||
}
|
||||
index_edit_has_focus = true;
|
||||
show_indices = true;
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_index_edit_focus_exited() {
|
||||
index_edit_has_focus = false;
|
||||
index_focus_cooldown_timer->start();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_index_focus_cooldown_timeout() {
|
||||
if (!index_edit_has_focus) {
|
||||
show_indices = false;
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_show_indices_with_cooldown() {
|
||||
if (index_focus_cooldown_timer->is_stopped() == false) {
|
||||
index_focus_cooldown_timer->stop();
|
||||
}
|
||||
show_indices = true;
|
||||
index_focus_cooldown_timer->start();
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled() {
|
||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||
undo_redo->create_action(TTR("Toggle Auto Triangles"));
|
||||
|
|
@ -883,6 +1070,106 @@ void AnimationNodeBlendSpace2DEditor::_bind_methods() {
|
|||
ClassDB::bind_method("_update_tool_erase", &AnimationNodeBlendSpace2DEditor::_update_tool_erase);
|
||||
|
||||
ClassDB::bind_method("_update_edited_point_pos", &AnimationNodeBlendSpace2DEditor::_update_edited_point_pos);
|
||||
ClassDB::bind_method("_update_edited_point_name", &AnimationNodeBlendSpace2DEditor::_update_edited_point_name);
|
||||
ClassDB::bind_method("_set_selected_point", &AnimationNodeBlendSpace2DEditor::_set_selected_point);
|
||||
ClassDB::bind_method("_show_indices_with_cooldown", &AnimationNodeBlendSpace2DEditor::_show_indices_with_cooldown);
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_start_inline_edit(int p_point) {
|
||||
if (editing_point != -1 || p_point < 0 || p_point >= blend_space->get_blend_point_count()) {
|
||||
return;
|
||||
}
|
||||
|
||||
editing_point = p_point;
|
||||
_set_selected_point(p_point);
|
||||
|
||||
inline_editor = memnew(LineEdit);
|
||||
blend_space_draw->add_child(inline_editor);
|
||||
|
||||
inline_editor->add_theme_color_override(SceneStringName(font_color), get_theme_color(SNAME("accent_color"), EditorStringName(Editor)));
|
||||
inline_editor->add_theme_color_override("font_selected_color", Color::named("white"));
|
||||
inline_editor->add_theme_color_override("selection_color", get_theme_color(SNAME("accent_color"), EditorStringName(Editor)));
|
||||
StyleBoxEmpty *empty_style = memnew(StyleBoxEmpty);
|
||||
empty_style->set_content_margin_all(0);
|
||||
inline_editor->add_theme_style_override(CoreStringName(normal), empty_style);
|
||||
inline_editor->add_theme_style_override("focus", memnew(StyleBoxEmpty));
|
||||
inline_editor->add_theme_style_override("read_only", memnew(StyleBoxEmpty));
|
||||
inline_editor->add_theme_constant_override("minimum_character_width", 0);
|
||||
inline_editor->set_flat(true);
|
||||
|
||||
inline_editor->set_text(blend_space->get_blend_point_name(p_point));
|
||||
inline_editor->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
|
||||
inline_editor->set_expand_to_text_length_enabled(true);
|
||||
|
||||
if (p_point < text_rects.size() && p_point < points.size()) {
|
||||
Rect2 text_rect = text_rects[p_point];
|
||||
|
||||
inline_editor_point_x = points[p_point].x;
|
||||
|
||||
float editor_width = text_rect.size.x;
|
||||
inline_editor->set_size(Vector2(editor_width, text_rect.size.y));
|
||||
|
||||
Size2 s = blend_space_draw->get_size();
|
||||
|
||||
float editor_x = inline_editor_point_x - editor_width / 2.0;
|
||||
editor_x = CLAMP(editor_x, 0.0f, s.width - editor_width);
|
||||
inline_editor->set_position(Vector2(editor_x, text_rect.position.y - 1 * EDSCALE));
|
||||
}
|
||||
|
||||
inline_editor->connect(SceneStringName(text_changed), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_inline_editor_text_changed));
|
||||
inline_editor->connect(SceneStringName(text_submitted), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_finish_inline_edit_with_text));
|
||||
inline_editor->connect(SceneStringName(focus_exited), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_finish_inline_edit));
|
||||
|
||||
inline_editor->grab_focus();
|
||||
inline_editor->select_all();
|
||||
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_finish_inline_edit() {
|
||||
if (editing_point == -1 || !inline_editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
String new_name = inline_editor->get_text();
|
||||
_edit_point_name(new_name);
|
||||
|
||||
_cancel_inline_edit();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_finish_inline_edit_with_text(const String &p_text) {
|
||||
if (editing_point == -1 || !inline_editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
_edit_point_name(p_text);
|
||||
|
||||
_cancel_inline_edit();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_cancel_inline_edit() {
|
||||
if (inline_editor) {
|
||||
inline_editor->queue_free();
|
||||
inline_editor = nullptr;
|
||||
}
|
||||
editing_point = -1;
|
||||
blend_space_draw->queue_redraw();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2DEditor::_inline_editor_text_changed(const String &p_text) {
|
||||
if (!inline_editor) {
|
||||
return;
|
||||
}
|
||||
|
||||
inline_editor->set_size(Vector2(0, inline_editor->get_size().y));
|
||||
|
||||
Vector2 editor_size = inline_editor->get_size();
|
||||
Size2 s = blend_space_draw->get_size();
|
||||
|
||||
float editor_x = inline_editor_point_x - editor_size.x / 2.0;
|
||||
editor_x = CLAMP(editor_x, 0.0f, s.width - editor_size.x);
|
||||
|
||||
inline_editor->set_position(Vector2(editor_x, inline_editor->get_position().y));
|
||||
}
|
||||
|
||||
AnimationNodeBlendSpace2DEditor *AnimationNodeBlendSpace2DEditor::singleton = nullptr;
|
||||
|
|
@ -903,7 +1190,7 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
|
|||
tool_select->set_button_group(bg);
|
||||
top_hb->add_child(tool_select);
|
||||
tool_select->set_pressed(true);
|
||||
tool_select->set_tooltip_text(TTR("Select and move points.\nRMB: Create point at position clicked.\nShift+LMB+Drag: Set the blending position within the space."));
|
||||
tool_select->set_tooltip_text(TTR("Select and move points.\nRMB: Create point at position clicked.\nShift+LMB+Drag: Set the blending position within the space.\nScroll: Increment or decrement index."));
|
||||
tool_select->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_tool_switch).bind(0));
|
||||
|
||||
tool_create = memnew(Button);
|
||||
|
|
@ -976,22 +1263,46 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
|
|||
|
||||
top_hb->add_child(memnew(VSeparator));
|
||||
|
||||
top_hb->add_child(memnew(Label(TTR("Sync:"))));
|
||||
top_hb->add_child(memnew(Label(TTR("Sync"))));
|
||||
sync = memnew(CheckBox);
|
||||
top_hb->add_child(sync);
|
||||
sync->connect(SceneStringName(toggled), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_config_changed));
|
||||
|
||||
top_hb->add_child(memnew(VSeparator));
|
||||
|
||||
top_hb->add_child(memnew(Label(TTR("Blend:"))));
|
||||
top_hb->add_child(memnew(Label(TTR("Blend"))));
|
||||
interpolation = memnew(OptionButton);
|
||||
top_hb->add_child(interpolation);
|
||||
interpolation->connect(SceneStringName(item_selected), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_config_changed));
|
||||
|
||||
top_hb->add_spacer();
|
||||
|
||||
edit_hb = memnew(HBoxContainer);
|
||||
top_hb->add_child(edit_hb);
|
||||
|
||||
open_editor = memnew(Button);
|
||||
edit_hb->add_child(open_editor);
|
||||
open_editor->set_text(TTR("Open Editor"));
|
||||
open_editor->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_open_editor), CONNECT_DEFERRED);
|
||||
open_editor_sep = memnew(VSeparator);
|
||||
edit_hb->add_child(open_editor_sep);
|
||||
|
||||
edit_hb->add_child(memnew(Label(TTR("Index"))));
|
||||
index_edit = memnew(SpinBox);
|
||||
edit_hb->add_child(index_edit);
|
||||
index_edit->set_min(0);
|
||||
index_edit->set_step(1);
|
||||
index_edit->set_allow_greater(false);
|
||||
index_edit->set_allow_lesser(false);
|
||||
index_edit->set_accessibility_name(TTRC("Blend Point Index"));
|
||||
index_edit->set_tooltip_text(TTR("Index of the blend point.\nValues outside of the valid range will be clamped to the nearest index."));
|
||||
index_edit->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_edit_point_index));
|
||||
index_edit->get_line_edit()->connect(SceneStringName(focus_entered), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_index_edit_focus_entered));
|
||||
index_edit->get_line_edit()->connect(SceneStringName(focus_exited), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_index_edit_focus_exited));
|
||||
|
||||
edit_hb->add_child(memnew(VSeparator));
|
||||
edit_hb->add_child(memnew(Label(TTR("Point"))));
|
||||
|
||||
edit_hb->add_child(memnew(Label(TTR("Position"))));
|
||||
edit_x = memnew(SpinBox);
|
||||
edit_hb->add_child(edit_x);
|
||||
edit_x->set_min(-1000);
|
||||
|
|
@ -1006,12 +1317,10 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
|
|||
edit_y->set_max(1000);
|
||||
edit_y->set_accessibility_name(TTRC("Blend Y Value"));
|
||||
edit_y->connect(SceneStringName(value_changed), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_edit_point_pos));
|
||||
open_editor = memnew(Button);
|
||||
edit_hb->add_child(open_editor);
|
||||
open_editor->set_text(TTR("Open Editor"));
|
||||
open_editor->connect(SceneStringName(pressed), callable_mp(this, &AnimationNodeBlendSpace2DEditor::_open_editor), CONNECT_DEFERRED);
|
||||
|
||||
edit_hb->hide();
|
||||
open_editor->hide();
|
||||
open_editor_sep->hide();
|
||||
|
||||
HBoxContainer *main_hb = memnew(HBoxContainer);
|
||||
add_child(main_hb);
|
||||
|
|
@ -1119,6 +1428,13 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
|
|||
open_file->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
|
||||
open_file->connect("file_selected", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_file_opened));
|
||||
|
||||
// Create timer for index focus cooldown (1.5 seconds).
|
||||
index_focus_cooldown_timer = memnew(Timer);
|
||||
add_child(index_focus_cooldown_timer);
|
||||
index_focus_cooldown_timer->set_wait_time(1.5);
|
||||
index_focus_cooldown_timer->set_one_shot(true);
|
||||
index_focus_cooldown_timer->connect("timeout", callable_mp(this, &AnimationNodeBlendSpace2DEditor::_index_focus_cooldown_timeout));
|
||||
|
||||
selected_point = -1;
|
||||
selected_triangle = -1;
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ class LineEdit;
|
|||
class OptionButton;
|
||||
class PanelContainer;
|
||||
class SpinBox;
|
||||
class Timer;
|
||||
class VSeparator;
|
||||
|
||||
class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
|
||||
|
|
@ -75,6 +76,8 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
|
|||
SpinBox *edit_x = nullptr;
|
||||
SpinBox *edit_y = nullptr;
|
||||
Button *open_editor = nullptr;
|
||||
VSeparator *open_editor_sep = nullptr;
|
||||
SpinBox *index_edit = nullptr;
|
||||
|
||||
int selected_point;
|
||||
int selected_triangle;
|
||||
|
|
@ -109,6 +112,14 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
|
|||
Vector2 drag_from;
|
||||
Vector2 drag_ofs;
|
||||
|
||||
Vector<Rect2> text_rects;
|
||||
int editing_point = -1;
|
||||
LineEdit *inline_editor = nullptr;
|
||||
float inline_editor_point_x = 0.0f;
|
||||
bool index_edit_has_focus = false;
|
||||
bool show_indices = false;
|
||||
Timer *index_focus_cooldown_timer = nullptr;
|
||||
|
||||
Vector<int> making_triangle;
|
||||
|
||||
void _add_menu_type(int p_index);
|
||||
|
|
@ -116,14 +127,28 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
|
|||
|
||||
void _tool_switch(int p_tool);
|
||||
void _update_edited_point_pos();
|
||||
void _update_edited_point_name();
|
||||
void _update_tool_erase();
|
||||
void _erase_selected();
|
||||
void _edit_point_pos(double);
|
||||
void _edit_point_name(const String &p_name);
|
||||
void _edit_point_index(double p_index);
|
||||
void _set_selected_point(int p_index);
|
||||
void _start_inline_edit(int p_point);
|
||||
void _finish_inline_edit();
|
||||
void _finish_inline_edit_with_text(const String &p_text);
|
||||
void _cancel_inline_edit();
|
||||
void _inline_editor_text_changed(const String &p_text);
|
||||
void _open_editor();
|
||||
void _index_edit_focus_entered();
|
||||
void _index_edit_focus_exited();
|
||||
void _index_focus_cooldown_timeout();
|
||||
void _show_indices_with_cooldown();
|
||||
|
||||
void _auto_triangles_toggled();
|
||||
|
||||
StringName get_blend_position_path() const;
|
||||
String _get_safe_name(const Ref<AnimationNodeBlendSpace2D> &p_blend_space, const String &p_name);
|
||||
|
||||
EditorFileDialog *open_file = nullptr;
|
||||
Ref<AnimationNode> file_loaded;
|
||||
|
|
@ -143,6 +168,7 @@ protected:
|
|||
|
||||
public:
|
||||
static AnimationNodeBlendSpace2DEditor *get_singleton() { return singleton; }
|
||||
void refresh_editor() { _update_space(); }
|
||||
virtual bool can_edit(const Ref<AnimationNode> &p_node) override;
|
||||
virtual void edit(const Ref<AnimationNode> &p_node) override;
|
||||
AnimationNodeBlendSpace2DEditor();
|
||||
|
|
|
|||
6
misc/extension_api_validation/4.6-stable/GH-110369.txt
Normal file
6
misc/extension_api_validation/4.6-stable/GH-110369.txt
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
GH-110369
|
||||
--------------
|
||||
Validate extension JSON: Error: Field 'classes/AnimationNodeBlendSpace2D/methods/add_blend_point/arguments': size changed value in new API, from 3 to 4.
|
||||
Validate extension JSON: Error: Field 'classes/AnimationNodeBlendSpace1D/methods/add_blend_point/arguments': size changed value in new API, from 3 to 4.
|
||||
|
||||
Added "name" parameter, to functionally replace index reference for points. Compatibility methods registered.
|
||||
49
scene/animation/animation_blend_space_1d.compat.inc
Normal file
49
scene/animation/animation_blend_space_1d.compat.inc
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/**************************************************************************/
|
||||
/* animation_blend_space_1d.compat.inc */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
#include "animation_blend_space_1d.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
void AnimationNodeBlendSpace1D::_add_blend_point_bind_compat_110369(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index) {
|
||||
int n = p_at_index == -1 ? blend_points_used : p_at_index;
|
||||
while (find_blend_point_by_name(itos(n)) != -1) {
|
||||
n++;
|
||||
}
|
||||
add_blend_point(p_node, p_position, p_at_index, StringName(itos(n)));
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace1D::_add_blend_point_bind_compat_110369, DEFVAL(-1));
|
||||
}
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
/**************************************************************************/
|
||||
|
||||
#include "animation_blend_space_1d.h"
|
||||
#include "animation_blend_space_1d.compat.inc"
|
||||
|
||||
#include "animation_blend_tree.h"
|
||||
|
||||
|
|
@ -54,17 +55,11 @@ Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName
|
|||
}
|
||||
|
||||
Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) const {
|
||||
return get_blend_point_node(p_name.operator String().to_int());
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &p_property) const {
|
||||
if (p_property.name.begins_with("blend_point_")) {
|
||||
String left = p_property.name.get_slicec('/', 0);
|
||||
int idx = left.get_slicec('_', 2).to_int();
|
||||
if (idx >= blend_points_used) {
|
||||
p_property.usage = PROPERTY_USAGE_NONE;
|
||||
}
|
||||
int point_index = find_blend_point_by_name(p_name);
|
||||
if (point_index != -1) {
|
||||
return get_blend_point_node(point_index);
|
||||
}
|
||||
return Ref<AnimationRootNode>();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::_tree_changed() {
|
||||
|
|
@ -80,13 +75,17 @@ void AnimationNodeBlendSpace1D::_animation_node_removed(const ObjectID &p_oid, c
|
|||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace1D::add_blend_point, DEFVAL(-1));
|
||||
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index", "name"), &AnimationNodeBlendSpace1D::add_blend_point, DEFVAL(-1), DEFVAL(StringName()));
|
||||
ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace1D::set_blend_point_position);
|
||||
ClassDB::bind_method(D_METHOD("get_blend_point_position", "point"), &AnimationNodeBlendSpace1D::get_blend_point_position);
|
||||
ClassDB::bind_method(D_METHOD("set_blend_point_node", "point", "node"), &AnimationNodeBlendSpace1D::set_blend_point_node);
|
||||
ClassDB::bind_method(D_METHOD("get_blend_point_node", "point"), &AnimationNodeBlendSpace1D::get_blend_point_node);
|
||||
ClassDB::bind_method(D_METHOD("set_blend_point_name", "point", "name"), &AnimationNodeBlendSpace1D::set_blend_point_name);
|
||||
ClassDB::bind_method(D_METHOD("get_blend_point_name", "point"), &AnimationNodeBlendSpace1D::get_blend_point_name);
|
||||
ClassDB::bind_method(D_METHOD("find_blend_point_by_name", "name"), &AnimationNodeBlendSpace1D::find_blend_point_by_name);
|
||||
ClassDB::bind_method(D_METHOD("remove_blend_point", "point"), &AnimationNodeBlendSpace1D::remove_blend_point);
|
||||
ClassDB::bind_method(D_METHOD("get_blend_point_count"), &AnimationNodeBlendSpace1D::get_blend_point_count);
|
||||
ClassDB::bind_method(D_METHOD("reorder_blend_point", "from_index", "to_index"), &AnimationNodeBlendSpace1D::reorder_blend_point);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_min_space", "min_space"), &AnimationNodeBlendSpace1D::set_min_space);
|
||||
ClassDB::bind_method(D_METHOD("get_min_space"), &AnimationNodeBlendSpace1D::get_min_space);
|
||||
|
|
@ -106,13 +105,6 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_use_sync", "enable"), &AnimationNodeBlendSpace1D::set_use_sync);
|
||||
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace1D::is_using_sync);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace1D::_add_blend_point);
|
||||
|
||||
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, AnimationRootNode::get_class_static(), PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_add_blend_point", "get_blend_point_node", i);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i);
|
||||
}
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_min_space", "get_min_space");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_max_space", "get_max_space");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_snap", "get_snap");
|
||||
|
|
@ -128,18 +120,25 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
|
|||
void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
ChildNode cn;
|
||||
cn.name = itos(i);
|
||||
cn.name = blend_points[i].name;
|
||||
cn.node = blend_points[i].node;
|
||||
r_child_nodes->push_back(cn);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index) {
|
||||
void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index, const StringName &p_name) {
|
||||
ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS);
|
||||
ERR_FAIL_COND(p_node.is_null());
|
||||
|
||||
ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used);
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (p_name == StringName()) {
|
||||
_add_blend_point_bind_compat_110369(p_node, p_position, p_at_index);
|
||||
WARN_PRINT_ED("AnimationNodeBlendSpace1D::add_blend_point: No name provided, using safe index as reference. In the future, empty names will be deprecated, so explicitly passing a name is recommended.");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
ERR_FAIL_COND(p_name == StringName());
|
||||
#endif
|
||||
if (p_at_index == -1 || p_at_index == blend_points_used) {
|
||||
p_at_index = blend_points_used;
|
||||
} else {
|
||||
|
|
@ -150,6 +149,7 @@ void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_
|
|||
|
||||
blend_points[p_at_index].node = p_node;
|
||||
blend_points[p_at_index].position = p_position;
|
||||
blend_points[p_at_index].name = p_name;
|
||||
|
||||
blend_points[p_at_index].node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace1D::_tree_changed), CONNECT_REFERENCE_COUNTED);
|
||||
blend_points[p_at_index].node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace1D::_animation_node_renamed), CONNECT_REFERENCE_COUNTED);
|
||||
|
|
@ -193,6 +193,32 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace1D::get_blend_point_node(int p_poi
|
|||
return blend_points[p_point].node;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::set_blend_point_name(int p_point, const StringName &p_name) {
|
||||
ERR_FAIL_INDEX(p_point, blend_points_used);
|
||||
String new_name = p_name;
|
||||
ERR_FAIL_COND(new_name.is_empty() || new_name.contains_char('.') || new_name.contains_char('/'));
|
||||
|
||||
String old_name = blend_points[p_point].name;
|
||||
if (new_name != old_name) {
|
||||
blend_points[p_point].name = p_name;
|
||||
emit_signal(SNAME("animation_node_renamed"), get_instance_id(), old_name, new_name);
|
||||
}
|
||||
}
|
||||
|
||||
StringName AnimationNodeBlendSpace1D::get_blend_point_name(int p_point) const {
|
||||
ERR_FAIL_INDEX_V(p_point, blend_points_used, StringName());
|
||||
return blend_points[p_point].name;
|
||||
}
|
||||
|
||||
int AnimationNodeBlendSpace1D::find_blend_point_by_name(const StringName &p_name) const {
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
if (blend_points[i].name == p_name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::remove_blend_point(int p_point) {
|
||||
ERR_FAIL_INDEX(p_point, blend_points_used);
|
||||
|
||||
|
|
@ -207,6 +233,8 @@ void AnimationNodeBlendSpace1D::remove_blend_point(int p_point) {
|
|||
|
||||
blend_points_used--;
|
||||
|
||||
blend_points[blend_points_used].name = StringName();
|
||||
|
||||
emit_signal(SNAME("animation_node_removed"), get_instance_id(), itos(p_point));
|
||||
emit_signal(SNAME("tree_changed"));
|
||||
}
|
||||
|
|
@ -215,6 +243,22 @@ int AnimationNodeBlendSpace1D::get_blend_point_count() const {
|
|||
return blend_points_used;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::reorder_blend_point(int p_from_index, int p_to_index) {
|
||||
ERR_FAIL_INDEX(p_from_index, blend_points_used);
|
||||
ERR_FAIL_INDEX(p_to_index, blend_points_used);
|
||||
|
||||
if (p_from_index == p_to_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
BlendPoint temp = blend_points[p_from_index];
|
||||
|
||||
blend_points[p_from_index] = blend_points[p_to_index];
|
||||
blend_points[p_to_index] = temp;
|
||||
|
||||
emit_signal(SNAME("tree_changed"));
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::set_min_space(float p_min) {
|
||||
min_space = p_min;
|
||||
|
||||
|
|
@ -271,11 +315,62 @@ bool AnimationNodeBlendSpace1D::is_using_sync() const {
|
|||
return sync;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::_add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node) {
|
||||
if (p_index == blend_points_used) {
|
||||
add_blend_point(p_node, 0);
|
||||
} else {
|
||||
set_blend_point_node(p_index, p_node);
|
||||
bool AnimationNodeBlendSpace1D::_set(const StringName &p_name, const Variant &p_value) {
|
||||
String prop = p_name;
|
||||
if (prop.begins_with("blend_point_")) {
|
||||
int idx = prop.get_slicec('_', 2).to_int();
|
||||
String what = prop.get_slicec('/', 1);
|
||||
if (what == "node") {
|
||||
Ref<AnimationRootNode> node = p_value;
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (idx == blend_points_used) {
|
||||
add_blend_point(node, 0, -1, blend_points[idx].name.is_empty() ? StringName(itos(idx)) : blend_points[idx].name);
|
||||
} else {
|
||||
set_blend_point_node(idx, node);
|
||||
}
|
||||
#else
|
||||
if (idx == blend_points_used) {
|
||||
add_blend_point(node, 0, -1, blend_points[idx].name);
|
||||
} else {
|
||||
set_blend_point_node(idx, node);
|
||||
}
|
||||
#endif // DISABLE_DEPRECATED
|
||||
} else if (what == "pos") {
|
||||
set_blend_point_position(idx, p_value);
|
||||
} else if (what == "name") {
|
||||
set_blend_point_name(idx, p_value);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AnimationNodeBlendSpace1D::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
String prop = p_name;
|
||||
if (prop.begins_with("blend_point_")) {
|
||||
int idx = prop.get_slicec('_', 2).to_int();
|
||||
String what = prop.get_slicec('/', 1);
|
||||
if (what == "node") {
|
||||
r_ret = get_blend_point_node(idx);
|
||||
} else if (what == "pos") {
|
||||
r_ret = get_blend_point_position(idx);
|
||||
} else if (what == "name") {
|
||||
r_ret = get_blend_point_name(idx);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
p_list->push_back(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, AnimationRootNode::get_class_static(), PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
|
||||
p_list->push_back(PropertyInfo(Variant::FLOAT, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, "blend_point_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -289,7 +384,7 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace1D::_process(const AnimationM
|
|||
if (blend_points_used == 1) {
|
||||
// only one point available, just play that animation
|
||||
pi.weight = 1.0;
|
||||
return blend_node(blend_points[0].node, blend_points[0].name, pi, FILTER_IGNORE, true, p_test_only);
|
||||
return blend_node(blend_points[0].node, get_blend_point_name(0), pi, FILTER_IGNORE, true, p_test_only);
|
||||
}
|
||||
|
||||
double blend_pos = get_parameter(blend_position);
|
||||
|
|
@ -352,7 +447,7 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace1D::_process(const AnimationM
|
|||
for (int i = 0; i < blend_points_used; i++) {
|
||||
if (i == point_lower || i == point_higher) {
|
||||
pi.weight = weights[i];
|
||||
NodeTimeInfo t = blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only);
|
||||
NodeTimeInfo t = blend_node(blend_points[i].node, get_blend_point_name(i), pi, FILTER_IGNORE, true, p_test_only);
|
||||
if (first || pi.weight > max_weight) {
|
||||
max_weight = pi.weight;
|
||||
mind = t;
|
||||
|
|
@ -360,7 +455,7 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace1D::_process(const AnimationM
|
|||
}
|
||||
} else if (sync) {
|
||||
pi.weight = 0;
|
||||
blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only);
|
||||
blend_node(blend_points[i].node, get_blend_point_name(i), pi, FILTER_IGNORE, true, p_test_only);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -393,16 +488,16 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace1D::_process(const AnimationM
|
|||
// See how much animation remains.
|
||||
pi.seeked = false;
|
||||
pi.weight = 0;
|
||||
from = blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, true);
|
||||
from = blend_node(blend_points[cur_closest].node, get_blend_point_name(cur_closest), pi, FILTER_IGNORE, true, true);
|
||||
pi.time = from.position;
|
||||
}
|
||||
pi.seeked = true;
|
||||
pi.weight = 1.0;
|
||||
mind = blend_node(blend_points[new_closest].node, blend_points[new_closest].name, pi, FILTER_IGNORE, true, p_test_only);
|
||||
mind = blend_node(blend_points[new_closest].node, get_blend_point_name(new_closest), pi, FILTER_IGNORE, true, p_test_only);
|
||||
cur_closest = new_closest;
|
||||
} else {
|
||||
pi.weight = 1.0;
|
||||
mind = blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, p_test_only);
|
||||
mind = blend_node(blend_points[cur_closest].node, get_blend_point_name(cur_closest), pi, FILTER_IGNORE, true, p_test_only);
|
||||
}
|
||||
|
||||
if (sync) {
|
||||
|
|
@ -410,7 +505,7 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace1D::_process(const AnimationM
|
|||
pi.weight = 0;
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
if (i != cur_closest) {
|
||||
blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only);
|
||||
blend_node(blend_points[i].node, get_blend_point_name(i), pi, FILTER_IGNORE, true, p_test_only);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -425,9 +520,6 @@ String AnimationNodeBlendSpace1D::get_caption() const {
|
|||
}
|
||||
|
||||
AnimationNodeBlendSpace1D::AnimationNodeBlendSpace1D() {
|
||||
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
|
||||
blend_points[i].name = itos(i);
|
||||
}
|
||||
}
|
||||
|
||||
AnimationNodeBlendSpace1D::~AnimationNodeBlendSpace1D() {
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ protected:
|
|||
|
||||
String value_label = "value";
|
||||
|
||||
void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node);
|
||||
bool _set(const StringName &p_name, const Variant &p_value);
|
||||
bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
StringName blend_position = "blend_position";
|
||||
StringName closest = "closest";
|
||||
|
|
@ -72,28 +74,37 @@ protected:
|
|||
|
||||
bool sync = false;
|
||||
|
||||
void _validate_property(PropertyInfo &p_property) const;
|
||||
static void _bind_methods();
|
||||
|
||||
virtual void _tree_changed() override;
|
||||
virtual void _animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) override;
|
||||
virtual void _animation_node_removed(const ObjectID &p_oid, const StringName &p_node) override;
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
void _add_blend_point_bind_compat_110369(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index = -1);
|
||||
static void _bind_compatibility_methods();
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
|
||||
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
|
||||
|
||||
virtual void get_child_nodes(List<ChildNode> *r_child_nodes) override;
|
||||
|
||||
void add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index = -1);
|
||||
void add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index = -1, const StringName &p_name = "");
|
||||
void set_blend_point_position(int p_point, float p_position);
|
||||
void set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node);
|
||||
|
||||
float get_blend_point_position(int p_point) const;
|
||||
Ref<AnimationRootNode> get_blend_point_node(int p_point) const;
|
||||
void set_blend_point_name(int p_point, const StringName &p_name);
|
||||
StringName get_blend_point_name(int p_point) const;
|
||||
int find_blend_point_by_name(const StringName &p_name) const;
|
||||
void remove_blend_point(int p_point);
|
||||
int get_blend_point_count() const;
|
||||
|
||||
void reorder_blend_point(int p_from_index, int p_to_index);
|
||||
|
||||
void set_min_space(float p_min);
|
||||
float get_min_space() const;
|
||||
|
||||
|
|
|
|||
49
scene/animation/animation_blend_space_2d.compat.inc
Normal file
49
scene/animation/animation_blend_space_2d.compat.inc
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/**************************************************************************/
|
||||
/* animation_blend_space_2d.compat.inc */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
|
||||
#include "animation_blend_space_2d.h"
|
||||
|
||||
#include "core/object/class_db.h"
|
||||
|
||||
void AnimationNodeBlendSpace2D::_add_blend_point_bind_compat_110369(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index) {
|
||||
int n = p_at_index == -1 ? blend_points_used : p_at_index;
|
||||
while (find_blend_point_by_name(itos(n)) != -1) {
|
||||
n++;
|
||||
}
|
||||
add_blend_point(p_node, p_position, p_at_index, StringName(itos(n)));
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2D::_bind_compatibility_methods() {
|
||||
ClassDB::bind_compatibility_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::_add_blend_point_bind_compat_110369, DEFVAL(-1));
|
||||
}
|
||||
|
||||
#endif // DISABLE_DEPRECATED
|
||||
|
|
@ -29,6 +29,7 @@
|
|||
/**************************************************************************/
|
||||
|
||||
#include "animation_blend_space_2d.h"
|
||||
#include "animation_blend_space_2d.compat.inc"
|
||||
|
||||
#include "animation_blend_tree.h"
|
||||
|
||||
|
|
@ -58,16 +59,25 @@ Variant AnimationNodeBlendSpace2D::get_parameter_default_value(const StringName
|
|||
void AnimationNodeBlendSpace2D::get_child_nodes(List<ChildNode> *r_child_nodes) {
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
ChildNode cn;
|
||||
cn.name = itos(i);
|
||||
cn.name = blend_points[i].name;
|
||||
cn.node = blend_points[i].node;
|
||||
r_child_nodes->push_back(cn);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index) {
|
||||
void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index, const StringName &p_name) {
|
||||
ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS);
|
||||
ERR_FAIL_COND(p_node.is_null());
|
||||
ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used);
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (p_name == StringName()) {
|
||||
_add_blend_point_bind_compat_110369(p_node, p_position, p_at_index);
|
||||
WARN_PRINT_ED("AnimationNodeBlendSpace2D::add_blend_point: No name provided, using safe index as reference. In the future, empty names will be deprecated, so explicitly passing a name is recommended.");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
ERR_FAIL_COND(p_name == StringName());
|
||||
#endif
|
||||
|
||||
if (p_at_index == -1 || p_at_index == blend_points_used) {
|
||||
p_at_index = blend_points_used;
|
||||
|
|
@ -85,6 +95,7 @@ void AnimationNodeBlendSpace2D::add_blend_point(const Ref<AnimationRootNode> &p_
|
|||
}
|
||||
blend_points[p_at_index].node = p_node;
|
||||
blend_points[p_at_index].position = p_position;
|
||||
blend_points[p_at_index].name = p_name;
|
||||
|
||||
blend_points[p_at_index].node->connect("tree_changed", callable_mp(this, &AnimationNodeBlendSpace2D::_tree_changed), CONNECT_REFERENCE_COUNTED);
|
||||
blend_points[p_at_index].node->connect("animation_node_renamed", callable_mp(this, &AnimationNodeBlendSpace2D::_animation_node_renamed), CONNECT_REFERENCE_COUNTED);
|
||||
|
|
@ -129,6 +140,32 @@ Ref<AnimationRootNode> AnimationNodeBlendSpace2D::get_blend_point_node(int p_poi
|
|||
return blend_points[p_point].node;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2D::set_blend_point_name(int p_point, const StringName &p_name) {
|
||||
ERR_FAIL_INDEX(p_point, blend_points_used);
|
||||
String new_name = p_name;
|
||||
ERR_FAIL_COND(new_name.is_empty() || new_name.contains_char('.') || new_name.contains_char('/'));
|
||||
|
||||
String old_name = blend_points[p_point].name;
|
||||
if (new_name != old_name) {
|
||||
blend_points[p_point].name = p_name;
|
||||
emit_signal(SNAME("animation_node_renamed"), get_instance_id(), old_name, p_name);
|
||||
}
|
||||
}
|
||||
|
||||
StringName AnimationNodeBlendSpace2D::get_blend_point_name(int p_point) const {
|
||||
ERR_FAIL_INDEX_V(p_point, blend_points_used, StringName());
|
||||
return blend_points[p_point].name;
|
||||
}
|
||||
|
||||
int AnimationNodeBlendSpace2D::find_blend_point_by_name(const StringName &p_name) const {
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
if (blend_points[i].name == p_name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
|
||||
ERR_FAIL_INDEX(p_point, blend_points_used);
|
||||
|
||||
|
|
@ -159,6 +196,8 @@ void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
|
|||
}
|
||||
blend_points_used--;
|
||||
|
||||
blend_points[blend_points_used].name = StringName();
|
||||
|
||||
emit_signal(SNAME("animation_node_removed"), get_instance_id(), itos(p_point));
|
||||
emit_signal(SNAME("tree_changed"));
|
||||
}
|
||||
|
|
@ -167,6 +206,38 @@ int AnimationNodeBlendSpace2D::get_blend_point_count() const {
|
|||
return blend_points_used;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2D::reorder_blend_point(int p_from_index, int p_to_index) {
|
||||
ERR_FAIL_INDEX(p_from_index, blend_points_used);
|
||||
ERR_FAIL_INDEX(p_to_index, blend_points_used);
|
||||
|
||||
if (p_from_index == p_to_index) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update triangle indices for swap operation
|
||||
for (int i = 0; i < triangles.size(); i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int point_ref = triangles[i].points[j];
|
||||
|
||||
if (point_ref == p_from_index) {
|
||||
triangles.write[i].points[j] = p_to_index;
|
||||
} else if (point_ref == p_to_index) {
|
||||
triangles.write[i].points[j] = p_from_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BlendPoint temp = blend_points[p_from_index];
|
||||
|
||||
blend_points[p_from_index] = blend_points[p_to_index];
|
||||
blend_points[p_to_index] = temp;
|
||||
|
||||
_queue_auto_triangles();
|
||||
|
||||
emit_signal(SNAME("tree_changed"));
|
||||
emit_signal(SNAME("triangles_updated"));
|
||||
}
|
||||
|
||||
bool AnimationNodeBlendSpace2D::has_triangle(int p_x, int p_y, int p_z) const {
|
||||
ERR_FAIL_INDEX_V(p_x, blend_points_used, false);
|
||||
ERR_FAIL_INDEX_V(p_y, blend_points_used, false);
|
||||
|
|
@ -299,14 +370,6 @@ String AnimationNodeBlendSpace2D::get_y_label() const {
|
|||
return y_label;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2D::_add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node) {
|
||||
if (p_index == blend_points_used) {
|
||||
add_blend_point(p_node, Vector2());
|
||||
} else {
|
||||
set_blend_point_node(p_index, p_node);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2D::_set_triangles(const Vector<int> &p_triangles) {
|
||||
if (auto_triangles) {
|
||||
return;
|
||||
|
|
@ -332,6 +395,65 @@ Vector<int> AnimationNodeBlendSpace2D::_get_triangles() const {
|
|||
return t;
|
||||
}
|
||||
|
||||
bool AnimationNodeBlendSpace2D::_set(const StringName &p_name, const Variant &p_value) {
|
||||
String prop = p_name;
|
||||
if (prop.begins_with("blend_point_")) {
|
||||
int idx = prop.get_slicec('_', 2).to_int();
|
||||
String what = prop.get_slicec('/', 1);
|
||||
if (what == "node") {
|
||||
Ref<AnimationRootNode> node = p_value;
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (idx == blend_points_used) {
|
||||
add_blend_point(node, Vector2(), -1, blend_points[idx].name.is_empty() ? StringName(itos(idx)) : blend_points[idx].name);
|
||||
} else {
|
||||
set_blend_point_node(idx, node);
|
||||
}
|
||||
#else
|
||||
if (idx == blend_points_used) {
|
||||
add_blend_point(node, Vector2(), -1, blend_points[idx].name);
|
||||
} else {
|
||||
set_blend_point_node(idx, node);
|
||||
}
|
||||
#endif // DISABLE_DEPRECATED
|
||||
} else if (what == "pos") {
|
||||
set_blend_point_position(idx, p_value);
|
||||
} else if (what == "name") {
|
||||
set_blend_point_name(idx, p_value);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AnimationNodeBlendSpace2D::_get(const StringName &p_name, Variant &r_ret) const {
|
||||
String prop = p_name;
|
||||
if (prop.begins_with("blend_point_")) {
|
||||
int idx = prop.get_slicec('_', 2).to_int();
|
||||
String what = prop.get_slicec('/', 1);
|
||||
if (what == "node") {
|
||||
r_ret = get_blend_point_node(idx);
|
||||
} else if (what == "pos") {
|
||||
r_ret = get_blend_point_position(idx);
|
||||
} else if (what == "name") {
|
||||
r_ret = get_blend_point_name(idx);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2D::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
p_list->push_back(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, AnimationRootNode::get_class_static(), PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR2, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, "blend_point_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2D::_queue_auto_triangles() {
|
||||
if (!auto_triangles || triangles_dirty) {
|
||||
return;
|
||||
|
|
@ -521,7 +643,7 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace2D::_process(const AnimationM
|
|||
if (i == triangle_points[j]) {
|
||||
//blend with the given weight
|
||||
pi.weight = blend_weights[j];
|
||||
NodeTimeInfo t = blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only);
|
||||
NodeTimeInfo t = blend_node(blend_points[i].node, get_blend_point_name(i), pi, FILTER_IGNORE, true, p_test_only);
|
||||
if (first || pi.weight > max_weight) {
|
||||
mind = t;
|
||||
max_weight = pi.weight;
|
||||
|
|
@ -534,7 +656,7 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace2D::_process(const AnimationM
|
|||
|
||||
if (sync && !found) {
|
||||
pi.weight = 0;
|
||||
blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only);
|
||||
blend_node(blend_points[i].node, get_blend_point_name(i), pi, FILTER_IGNORE, true, p_test_only);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -567,16 +689,16 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace2D::_process(const AnimationM
|
|||
// See how much animation remains.
|
||||
pi.seeked = false;
|
||||
pi.weight = 0;
|
||||
from = blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, true);
|
||||
from = blend_node(blend_points[cur_closest].node, get_blend_point_name(cur_closest), pi, FILTER_IGNORE, true, true);
|
||||
pi.time = from.position;
|
||||
}
|
||||
pi.seeked = true;
|
||||
pi.weight = 1.0;
|
||||
mind = blend_node(blend_points[new_closest].node, blend_points[new_closest].name, pi, FILTER_IGNORE, true, p_test_only);
|
||||
mind = blend_node(blend_points[new_closest].node, get_blend_point_name(new_closest), pi, FILTER_IGNORE, true, p_test_only);
|
||||
cur_closest = new_closest;
|
||||
} else {
|
||||
pi.weight = 1.0;
|
||||
mind = blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, p_test_only);
|
||||
mind = blend_node(blend_points[cur_closest].node, get_blend_point_name(cur_closest), pi, FILTER_IGNORE, true, p_test_only);
|
||||
}
|
||||
|
||||
if (sync) {
|
||||
|
|
@ -584,7 +706,7 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace2D::_process(const AnimationM
|
|||
pi.weight = 0;
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
if (i != cur_closest) {
|
||||
blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only);
|
||||
blend_node(blend_points[i].node, get_blend_point_name(i), pi, FILTER_IGNORE, true, p_test_only);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -601,12 +723,6 @@ String AnimationNodeBlendSpace2D::get_caption() const {
|
|||
void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &p_property) const {
|
||||
if (auto_triangles && p_property.name == "triangles") {
|
||||
p_property.usage = PROPERTY_USAGE_NONE;
|
||||
} else if (p_property.name.begins_with("blend_point_")) {
|
||||
String left = p_property.name.get_slicec('/', 0);
|
||||
int idx = left.get_slicec('_', 2).to_int();
|
||||
if (idx >= blend_points_used) {
|
||||
p_property.usage = PROPERTY_USAGE_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -624,7 +740,11 @@ bool AnimationNodeBlendSpace2D::get_auto_triangles() const {
|
|||
}
|
||||
|
||||
Ref<AnimationNode> AnimationNodeBlendSpace2D::get_child_by_name(const StringName &p_name) const {
|
||||
return get_blend_point_node(p_name.operator String().to_int());
|
||||
int point_index = find_blend_point_by_name(p_name);
|
||||
if (point_index != -1) {
|
||||
return get_blend_point_node(point_index);
|
||||
}
|
||||
return Ref<AnimationRootNode>();
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace2D::set_blend_mode(BlendMode p_blend_mode) {
|
||||
|
|
@ -656,13 +776,17 @@ void AnimationNodeBlendSpace2D::_animation_node_removed(const ObjectID &p_oid, c
|
|||
}
|
||||
|
||||
void AnimationNodeBlendSpace2D::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1));
|
||||
ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index", "name"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1), DEFVAL(StringName()));
|
||||
ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace2D::set_blend_point_position);
|
||||
ClassDB::bind_method(D_METHOD("get_blend_point_position", "point"), &AnimationNodeBlendSpace2D::get_blend_point_position);
|
||||
ClassDB::bind_method(D_METHOD("set_blend_point_node", "point", "node"), &AnimationNodeBlendSpace2D::set_blend_point_node);
|
||||
ClassDB::bind_method(D_METHOD("get_blend_point_node", "point"), &AnimationNodeBlendSpace2D::get_blend_point_node);
|
||||
ClassDB::bind_method(D_METHOD("set_blend_point_name", "point", "name"), &AnimationNodeBlendSpace2D::set_blend_point_name);
|
||||
ClassDB::bind_method(D_METHOD("get_blend_point_name", "point"), &AnimationNodeBlendSpace2D::get_blend_point_name);
|
||||
ClassDB::bind_method(D_METHOD("find_blend_point_by_name", "name"), &AnimationNodeBlendSpace2D::find_blend_point_by_name);
|
||||
ClassDB::bind_method(D_METHOD("remove_blend_point", "point"), &AnimationNodeBlendSpace2D::remove_blend_point);
|
||||
ClassDB::bind_method(D_METHOD("get_blend_point_count"), &AnimationNodeBlendSpace2D::get_blend_point_count);
|
||||
ClassDB::bind_method(D_METHOD("reorder_blend_point", "from_index", "to_index"), &AnimationNodeBlendSpace2D::reorder_blend_point);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_triangle", "x", "y", "z", "at_index"), &AnimationNodeBlendSpace2D::add_triangle, DEFVAL(-1));
|
||||
ClassDB::bind_method(D_METHOD("get_triangle_point", "triangle", "point"), &AnimationNodeBlendSpace2D::get_triangle_point);
|
||||
|
|
@ -684,8 +808,6 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_y_label", "text"), &AnimationNodeBlendSpace2D::set_y_label);
|
||||
ClassDB::bind_method(D_METHOD("get_y_label"), &AnimationNodeBlendSpace2D::get_y_label);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace2D::_add_blend_point);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("_set_triangles", "triangles"), &AnimationNodeBlendSpace2D::_set_triangles);
|
||||
ClassDB::bind_method(D_METHOD("_get_triangles"), &AnimationNodeBlendSpace2D::_get_triangles);
|
||||
|
||||
|
|
@ -699,12 +821,6 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("is_using_sync"), &AnimationNodeBlendSpace2D::is_using_sync);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_auto_triangles", "get_auto_triangles");
|
||||
|
||||
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "blend_point_" + itos(i) + "/node", PROPERTY_HINT_RESOURCE_TYPE, AnimationRootNode::get_class_static(), PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_add_blend_point", "get_blend_point_node", i);
|
||||
ADD_PROPERTYI(PropertyInfo(Variant::VECTOR2, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i);
|
||||
}
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_triangles", "_get_triangles");
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_min_space", "get_min_space");
|
||||
|
|
@ -722,9 +838,6 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
|
|||
}
|
||||
|
||||
AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() {
|
||||
for (int i = 0; i < MAX_BLEND_POINTS; i++) {
|
||||
blend_points[i].name = itos(i);
|
||||
}
|
||||
}
|
||||
|
||||
AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,10 @@ protected:
|
|||
String y_label = "y";
|
||||
BlendMode blend_mode = BLEND_MODE_INTERPOLATED;
|
||||
|
||||
void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node);
|
||||
bool _set(const StringName &p_name, const Variant &p_value);
|
||||
bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
|
||||
void _set_triangles(const Vector<int> &p_triangles);
|
||||
Vector<int> _get_triangles() const;
|
||||
|
||||
|
|
@ -92,20 +95,30 @@ protected:
|
|||
virtual void _animation_node_renamed(const ObjectID &p_oid, const String &p_old_name, const String &p_new_name) override;
|
||||
virtual void _animation_node_removed(const ObjectID &p_oid, const StringName &p_node) override;
|
||||
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
void _add_blend_point_bind_compat_110369(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index = -1);
|
||||
static void _bind_compatibility_methods();
|
||||
#endif
|
||||
|
||||
public:
|
||||
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
|
||||
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
|
||||
|
||||
virtual void get_child_nodes(List<ChildNode> *r_child_nodes) override;
|
||||
|
||||
void add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index = -1);
|
||||
void add_blend_point(const Ref<AnimationRootNode> &p_node, const Vector2 &p_position, int p_at_index = -1, const StringName &p_name = StringName());
|
||||
void set_blend_point_position(int p_point, const Vector2 &p_position);
|
||||
void set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node);
|
||||
void set_blend_point_name(int p_point, const StringName &p_name);
|
||||
StringName get_blend_point_name(int p_point) const;
|
||||
int find_blend_point_by_name(const StringName &p_name) const;
|
||||
Vector2 get_blend_point_position(int p_point) const;
|
||||
Ref<AnimationRootNode> get_blend_point_node(int p_point) const;
|
||||
void remove_blend_point(int p_point);
|
||||
int get_blend_point_count() const;
|
||||
|
||||
void reorder_blend_point(int p_from_index, int p_to_index);
|
||||
|
||||
bool has_triangle(int p_x, int p_y, int p_z) const;
|
||||
void add_triangle(int p_x, int p_y, int p_z, int p_at_index = -1);
|
||||
int get_triangle_point(int p_triangle, int p_point);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue