Merge pull request #72396 from TokageItLab/bs1dconsist
Consistent with NodeBlendSpace1D option NodeBlendSpace2D
This commit is contained in:
commit
92a6586fb6
|
@ -67,6 +67,9 @@
|
|||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="blend_mode" type="int" setter="set_blend_mode" getter="get_blend_mode" enum="AnimationNodeBlendSpace1D.BlendMode" default="0">
|
||||
Controls the interpolation between animations. See [enum BlendMode] constants.
|
||||
</member>
|
||||
<member name="max_space" type="float" setter="set_max_space" getter="get_max_space" default="1.0">
|
||||
The blend space's axis's upper limit for the points' position. See [method add_blend_point].
|
||||
</member>
|
||||
|
@ -84,4 +87,15 @@
|
|||
Label of the virtual axis of the blend space.
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
<constant name="BLEND_MODE_INTERPOLATED" value="0" enum="BlendMode">
|
||||
The interpolation between animations is linear.
|
||||
</constant>
|
||||
<constant name="BLEND_MODE_DISCRETE" value="1" enum="BlendMode">
|
||||
The blend space plays the animation of the node the blending position is closest to. Useful for frame-by-frame 2D animations.
|
||||
</constant>
|
||||
<constant name="BLEND_MODE_DISCRETE_CARRY" value="2" enum="BlendMode">
|
||||
Similar to [constant BLEND_MODE_DISCRETE], but starts the new animation at the last animation's playback position.
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "editor/editor_undo_redo_manager.h"
|
||||
#include "scene/animation/animation_blend_tree.h"
|
||||
#include "scene/gui/check_box.h"
|
||||
#include "scene/gui/option_button.h"
|
||||
#include "scene/gui/panel_container.h"
|
||||
|
||||
StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const {
|
||||
|
@ -335,6 +336,7 @@ void AnimationNodeBlendSpace1DEditor::_update_space() {
|
|||
min_value->set_value(blend_space->get_min_space());
|
||||
|
||||
sync->set_pressed(blend_space->is_using_sync());
|
||||
interpolation->select(blend_space->get_blend_mode());
|
||||
|
||||
label_value->set_text(blend_space->get_value_label());
|
||||
|
||||
|
@ -361,6 +363,8 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) {
|
|||
undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap());
|
||||
undo_redo->add_do_method(blend_space.ptr(), "set_use_sync", sync->is_pressed());
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "set_use_sync", blend_space->is_using_sync());
|
||||
undo_redo->add_do_method(blend_space.ptr(), "set_blend_mode", interpolation->get_selected());
|
||||
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_mode", blend_space->get_blend_mode());
|
||||
undo_redo->add_do_method(this, "_update_space");
|
||||
undo_redo->add_undo_method(this, "_update_space");
|
||||
undo_redo->commit_action();
|
||||
|
@ -579,6 +583,10 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) {
|
|||
tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
|
||||
snap->set_icon(get_theme_icon(SNAME("SnapGrid"), SNAME("EditorIcons")));
|
||||
open_editor->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
|
||||
interpolation->clear();
|
||||
interpolation->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), "", 0);
|
||||
interpolation->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), "", 1);
|
||||
interpolation->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), "", 2);
|
||||
} break;
|
||||
|
||||
case NOTIFICATION_PROCESS: {
|
||||
|
@ -639,6 +647,7 @@ void AnimationNodeBlendSpace1DEditor::edit(const Ref<AnimationNode> &p_node) {
|
|||
min_value->set_editable(!read_only);
|
||||
max_value->set_editable(!read_only);
|
||||
sync->set_disabled(read_only);
|
||||
interpolation->set_disabled(read_only);
|
||||
}
|
||||
|
||||
AnimationNodeBlendSpace1DEditor *AnimationNodeBlendSpace1DEditor::singleton = nullptr;
|
||||
|
@ -707,6 +716,13 @@ AnimationNodeBlendSpace1DEditor::AnimationNodeBlendSpace1DEditor() {
|
|||
top_hb->add_child(sync);
|
||||
sync->connect("toggled", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
|
||||
|
||||
top_hb->add_child(memnew(VSeparator));
|
||||
|
||||
top_hb->add_child(memnew(Label(TTR("Blend:"))));
|
||||
interpolation = memnew(OptionButton);
|
||||
top_hb->add_child(interpolation);
|
||||
interpolation->connect("item_selected", callable_mp(this, &AnimationNodeBlendSpace1DEditor::_config_changed));
|
||||
|
||||
edit_hb = memnew(HBoxContainer);
|
||||
top_hb->add_child(edit_hb);
|
||||
edit_hb->add_child(memnew(VSeparator));
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "scene/gui/tree.h"
|
||||
|
||||
class CheckBox;
|
||||
class OptionButton;
|
||||
class PanelContainer;
|
||||
|
||||
class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
|
||||
|
@ -66,6 +67,7 @@ class AnimationNodeBlendSpace1DEditor : public AnimationTreeNodeEditorPlugin {
|
|||
SpinBox *min_value = nullptr;
|
||||
|
||||
CheckBox *sync = nullptr;
|
||||
OptionButton *interpolation = nullptr;
|
||||
|
||||
HBoxContainer *edit_hb = nullptr;
|
||||
SpinBox *edit_value = nullptr;
|
||||
|
|
|
@ -30,12 +30,20 @@
|
|||
|
||||
#include "animation_blend_space_1d.h"
|
||||
|
||||
#include "animation_blend_tree.h"
|
||||
|
||||
void AnimationNodeBlendSpace1D::get_parameter_list(List<PropertyInfo> *r_list) const {
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_position));
|
||||
r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||
r_list->push_back(PropertyInfo(Variant::FLOAT, length_internal, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
|
||||
}
|
||||
|
||||
Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName &p_parameter) const {
|
||||
return 0;
|
||||
if (p_parameter == closest) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) {
|
||||
|
@ -77,6 +85,9 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_value_label", "text"), &AnimationNodeBlendSpace1D::set_value_label);
|
||||
ClassDB::bind_method(D_METHOD("get_value_label"), &AnimationNodeBlendSpace1D::get_value_label);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &AnimationNodeBlendSpace1D::set_blend_mode);
|
||||
ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace1D::get_blend_mode);
|
||||
|
||||
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);
|
||||
|
||||
|
@ -91,7 +102,12 @@ void AnimationNodeBlendSpace1D::_bind_methods() {
|
|||
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");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_value_label", "get_value_label");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NO_EDITOR), "set_blend_mode", "get_blend_mode");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sync", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_use_sync", "is_using_sync");
|
||||
|
||||
BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED);
|
||||
BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE);
|
||||
BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE_CARRY);
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::get_child_nodes(List<ChildNode> *r_child_nodes) {
|
||||
|
@ -214,6 +230,14 @@ String AnimationNodeBlendSpace1D::get_value_label() const {
|
|||
return value_label;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::set_blend_mode(BlendMode p_blend_mode) {
|
||||
blend_mode = p_blend_mode;
|
||||
}
|
||||
|
||||
AnimationNodeBlendSpace1D::BlendMode AnimationNodeBlendSpace1D::get_blend_mode() const {
|
||||
return blend_mode;
|
||||
}
|
||||
|
||||
void AnimationNodeBlendSpace1D::set_use_sync(bool p_sync) {
|
||||
sync = p_sync;
|
||||
}
|
||||
|
@ -241,79 +265,125 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_is_
|
|||
}
|
||||
|
||||
double blend_pos = get_parameter(blend_position);
|
||||
|
||||
float weights[MAX_BLEND_POINTS] = {};
|
||||
|
||||
int point_lower = -1;
|
||||
float pos_lower = 0.0;
|
||||
int point_higher = -1;
|
||||
float pos_higher = 0.0;
|
||||
|
||||
// find the closest two points to blend between
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
float pos = blend_points[i].position;
|
||||
|
||||
if (pos <= blend_pos) {
|
||||
if (point_lower == -1) {
|
||||
point_lower = i;
|
||||
pos_lower = pos;
|
||||
} else if ((blend_pos - pos) < (blend_pos - pos_lower)) {
|
||||
point_lower = i;
|
||||
pos_lower = pos;
|
||||
}
|
||||
} else {
|
||||
if (point_higher == -1) {
|
||||
point_higher = i;
|
||||
pos_higher = pos;
|
||||
} else if ((pos - blend_pos) < (pos_higher - blend_pos)) {
|
||||
point_higher = i;
|
||||
pos_higher = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fill in weights
|
||||
|
||||
if (point_lower == -1 && point_higher != -1) {
|
||||
// we are on the left side, no other point to the left
|
||||
// we just play the next point.
|
||||
|
||||
weights[point_higher] = 1.0;
|
||||
} else if (point_higher == -1) {
|
||||
// we are on the right side, no other point to the right
|
||||
// we just play the previous point
|
||||
|
||||
weights[point_lower] = 1.0;
|
||||
} else {
|
||||
// we are between two points.
|
||||
// figure out weights, then blend the animations
|
||||
|
||||
float distance_between_points = pos_higher - pos_lower;
|
||||
|
||||
float current_pos_inbetween = blend_pos - pos_lower;
|
||||
|
||||
float blend_percentage = current_pos_inbetween / distance_between_points;
|
||||
|
||||
float blend_lower = 1.0 - blend_percentage;
|
||||
float blend_higher = blend_percentage;
|
||||
|
||||
weights[point_lower] = blend_lower;
|
||||
weights[point_higher] = blend_higher;
|
||||
}
|
||||
|
||||
// actually blend the animations now
|
||||
|
||||
int cur_closest = get_parameter(closest);
|
||||
double cur_length_internal = get_parameter(length_internal);
|
||||
double max_time_remaining = 0.0;
|
||||
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
if (i == point_lower || i == point_higher) {
|
||||
double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true);
|
||||
max_time_remaining = MAX(max_time_remaining, remaining);
|
||||
} else if (sync) {
|
||||
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
||||
if (blend_mode == BLEND_MODE_INTERPOLATED) {
|
||||
float weights[MAX_BLEND_POINTS] = {};
|
||||
|
||||
int point_lower = -1;
|
||||
float pos_lower = 0.0;
|
||||
int point_higher = -1;
|
||||
float pos_higher = 0.0;
|
||||
|
||||
// find the closest two points to blend between
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
float pos = blend_points[i].position;
|
||||
|
||||
if (pos <= blend_pos) {
|
||||
if (point_lower == -1) {
|
||||
point_lower = i;
|
||||
pos_lower = pos;
|
||||
} else if ((blend_pos - pos) < (blend_pos - pos_lower)) {
|
||||
point_lower = i;
|
||||
pos_lower = pos;
|
||||
}
|
||||
} else {
|
||||
if (point_higher == -1) {
|
||||
point_higher = i;
|
||||
pos_higher = pos;
|
||||
} else if ((pos - blend_pos) < (pos_higher - blend_pos)) {
|
||||
point_higher = i;
|
||||
pos_higher = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fill in weights
|
||||
|
||||
if (point_lower == -1 && point_higher != -1) {
|
||||
// we are on the left side, no other point to the left
|
||||
// we just play the next point.
|
||||
|
||||
weights[point_higher] = 1.0;
|
||||
} else if (point_higher == -1) {
|
||||
// we are on the right side, no other point to the right
|
||||
// we just play the previous point
|
||||
|
||||
weights[point_lower] = 1.0;
|
||||
} else {
|
||||
// we are between two points.
|
||||
// figure out weights, then blend the animations
|
||||
|
||||
float distance_between_points = pos_higher - pos_lower;
|
||||
|
||||
float current_pos_inbetween = blend_pos - pos_lower;
|
||||
|
||||
float blend_percentage = current_pos_inbetween / distance_between_points;
|
||||
|
||||
float blend_lower = 1.0 - blend_percentage;
|
||||
float blend_higher = blend_percentage;
|
||||
|
||||
weights[point_lower] = blend_lower;
|
||||
weights[point_higher] = blend_higher;
|
||||
}
|
||||
|
||||
// actually blend the animations now
|
||||
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
if (i == point_lower || i == point_higher) {
|
||||
double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true);
|
||||
max_time_remaining = MAX(max_time_remaining, remaining);
|
||||
} else if (sync) {
|
||||
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int new_closest = -1;
|
||||
double new_closest_dist = 1e20;
|
||||
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
double d = abs(blend_points[i].position - blend_pos);
|
||||
if (d < new_closest_dist) {
|
||||
new_closest = i;
|
||||
new_closest_dist = d;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_closest != cur_closest && new_closest != -1) {
|
||||
double from = 0.0;
|
||||
if (blend_mode == BLEND_MODE_DISCRETE_CARRY && cur_closest != -1) {
|
||||
//for ping-pong loop
|
||||
Ref<AnimationNodeAnimation> na_c = static_cast<Ref<AnimationNodeAnimation>>(blend_points[cur_closest].node);
|
||||
Ref<AnimationNodeAnimation> na_n = static_cast<Ref<AnimationNodeAnimation>>(blend_points[new_closest].node);
|
||||
if (!na_c.is_null() && !na_n.is_null()) {
|
||||
na_n->set_backward(na_c->is_backward());
|
||||
}
|
||||
//see how much animation remains
|
||||
from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_is_external_seeking, 0.0, FILTER_IGNORE, true);
|
||||
}
|
||||
|
||||
max_time_remaining = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
||||
cur_length_internal = from + max_time_remaining;
|
||||
|
||||
cur_closest = new_closest;
|
||||
|
||||
} else {
|
||||
max_time_remaining = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
||||
}
|
||||
|
||||
if (sync) {
|
||||
for (int i = 0; i < blend_points_used; i++) {
|
||||
if (i != cur_closest) {
|
||||
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_parameter(this->closest, cur_closest);
|
||||
set_parameter(this->length_internal, cur_length_internal);
|
||||
return max_time_remaining;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,14 @@
|
|||
class AnimationNodeBlendSpace1D : public AnimationRootNode {
|
||||
GDCLASS(AnimationNodeBlendSpace1D, AnimationRootNode);
|
||||
|
||||
public:
|
||||
enum BlendMode {
|
||||
BLEND_MODE_INTERPOLATED,
|
||||
BLEND_MODE_DISCRETE,
|
||||
BLEND_MODE_DISCRETE_CARRY,
|
||||
};
|
||||
|
||||
protected:
|
||||
enum {
|
||||
MAX_BLEND_POINTS = 64
|
||||
};
|
||||
|
@ -61,6 +69,10 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode {
|
|||
void _tree_changed();
|
||||
|
||||
StringName blend_position = "blend_position";
|
||||
StringName closest = "closest";
|
||||
StringName length_internal = "length_internal";
|
||||
|
||||
BlendMode blend_mode = BLEND_MODE_INTERPOLATED;
|
||||
|
||||
protected:
|
||||
bool sync = false;
|
||||
|
@ -95,6 +107,9 @@ public:
|
|||
void set_value_label(const String &p_label);
|
||||
String get_value_label() const;
|
||||
|
||||
void set_blend_mode(BlendMode p_blend_mode);
|
||||
BlendMode get_blend_mode() const;
|
||||
|
||||
void set_use_sync(bool p_sync);
|
||||
bool is_using_sync() const;
|
||||
|
||||
|
@ -107,4 +122,6 @@ public:
|
|||
~AnimationNodeBlendSpace1D();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(AnimationNodeBlendSpace1D::BlendMode)
|
||||
|
||||
#endif // ANIMATION_BLEND_SPACE_1D_H
|
||||
|
|
Loading…
Reference in New Issue