Add Discrete and Carry blend modes for BlendSpace2D, allows to fix #20135

This commit is contained in:
Juan Linietsky 2018-11-21 16:06:17 -03:00
parent 03bd4d28a5
commit 9018e8b132
4 changed files with 164 additions and 66 deletions

View file

@ -607,6 +607,8 @@ void AnimationNodeBlendSpace2DEditor::_update_space() {
auto_triangles->set_pressed(blend_space->get_auto_triangles()); auto_triangles->set_pressed(blend_space->get_auto_triangles());
interpolation->select(blend_space->get_blend_mode());
max_x_value->set_value(blend_space->get_max_space().x); max_x_value->set_value(blend_space->get_max_space().x);
max_y_value->set_value(blend_space->get_max_space().y); max_y_value->set_value(blend_space->get_max_space().y);
@ -636,6 +638,8 @@ void AnimationNodeBlendSpace2DEditor::_config_changed(double) {
undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space()); undo_redo->add_undo_method(blend_space.ptr(), "set_min_space", blend_space->get_min_space());
undo_redo->add_do_method(blend_space.ptr(), "set_snap", Vector2(snap_x->get_value(), snap_y->get_value())); undo_redo->add_do_method(blend_space.ptr(), "set_snap", Vector2(snap_x->get_value(), snap_y->get_value()));
undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap()); undo_redo->add_undo_method(blend_space.ptr(), "set_snap", blend_space->get_snap());
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_do_method(this, "_update_space");
undo_redo->add_undo_method(this, "_update_space"); undo_redo->add_undo_method(this, "_update_space");
undo_redo->commit_action(); undo_redo->commit_action();
@ -752,6 +756,10 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
snap->set_icon(get_icon("SnapGrid", "EditorIcons")); snap->set_icon(get_icon("SnapGrid", "EditorIcons"));
open_editor->set_icon(get_icon("Edit", "EditorIcons")); open_editor->set_icon(get_icon("Edit", "EditorIcons"));
auto_triangles->set_icon(get_icon("AutoTriangle", "EditorIcons")); auto_triangles->set_icon(get_icon("AutoTriangle", "EditorIcons"));
interpolation->clear();
interpolation->add_icon_item(get_icon("TrackContinuous", "EditorIcons"), "", 0);
interpolation->add_icon_item(get_icon("TrackDiscrete", "EditorIcons"), "", 1);
interpolation->add_icon_item(get_icon("TrackCapture", "EditorIcons"), "", 2);
} }
if (p_what == NOTIFICATION_PROCESS) { if (p_what == NOTIFICATION_PROCESS) {
@ -914,6 +922,13 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
snap_y->set_step(0.01); snap_y->set_step(0.01);
snap_y->set_max(1000); snap_y->set_max(1000);
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", this, "_config_changed");
edit_hb = memnew(HBoxContainer); edit_hb = memnew(HBoxContainer);
top_hb->add_child(edit_hb); top_hb->add_child(edit_hb);
edit_hb->add_child(memnew(VSeparator)); edit_hb->add_child(memnew(VSeparator));

View file

@ -60,6 +60,7 @@ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin {
ToolButton *snap; ToolButton *snap;
SpinBox *snap_x; SpinBox *snap_x;
SpinBox *snap_y; SpinBox *snap_y;
OptionButton *interpolation;
ToolButton *auto_triangles; ToolButton *auto_triangles;

View file

@ -33,9 +33,17 @@
void AnimationNodeBlendSpace2D::get_parameter_list(List<PropertyInfo> *r_list) const { void AnimationNodeBlendSpace2D::get_parameter_list(List<PropertyInfo> *r_list) const {
r_list->push_back(PropertyInfo(Variant::VECTOR2, blend_position)); r_list->push_back(PropertyInfo(Variant::VECTOR2, blend_position));
r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", 0));
r_list->push_back(PropertyInfo(Variant::REAL, length_internal, PROPERTY_HINT_NONE, "", 0));
} }
Variant AnimationNodeBlendSpace2D::get_parameter_default_value(const StringName &p_parameter) const { Variant AnimationNodeBlendSpace2D::get_parameter_default_value(const StringName &p_parameter) const {
if (p_parameter == closest) {
return -1;
} else if (p_parameter == length_internal) {
return 0;
} else {
return Vector2(); return Vector2();
}
} }
void AnimationNodeBlendSpace2D::get_child_nodes(List<ChildNode> *r_child_nodes) { void AnimationNodeBlendSpace2D::get_child_nodes(List<ChildNode> *r_child_nodes) {
@ -412,6 +420,11 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
_update_triangles(); _update_triangles();
Vector2 blend_pos = get_parameter(blend_position); Vector2 blend_pos = get_parameter(blend_position);
int closest = get_parameter(this->closest);
float length_internal = get_parameter(this->length_internal);
float mind = 0; //time of min distance point
if (blend_mode == BLEND_MODE_INTERPOLATED) {
if (triangles.size() == 0) if (triangles.size() == 0)
return 0; return 0;
@ -468,7 +481,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
} }
first = true; first = true;
float mind = 0;
for (int i = 0; i < blend_points_used; i++) { for (int i = 0; i < blend_points_used; i++) {
bool found = false; bool found = false;
@ -490,6 +503,41 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false); blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false);
} }
} }
} else {
int new_closest = -1;
float new_closest_dist = 1e20;
for (int i = 0; i < blend_points_used; i++) {
float d = blend_points[i].position.distance_squared_to(blend_pos);
if (d < new_closest_dist) {
new_closest = i;
new_closest_dist = d;
}
}
if (new_closest != closest) {
float from = 0;
if (blend_mode == BLEND_MODE_DISCRETE_CARRY && closest != -1) {
//see how much animation remains
from = blend_node(blend_points[closest].name, blend_points[closest].node, p_time, true, 0.0, FILTER_IGNORE, false) - length_internal;
}
mind = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, 1.0, FILTER_IGNORE, false) + from;
length_internal = from + mind;
closest = new_closest;
} else {
mind = blend_node(blend_points[closest].name, blend_points[closest].node, p_time, p_seek, 1.0, FILTER_IGNORE, false);
}
}
set_parameter(this->closest, closest);
set_parameter(this->length_internal, length_internal);
return mind; return mind;
} }
@ -527,6 +575,14 @@ void AnimationNodeBlendSpace2D::_tree_changed() {
emit_signal("tree_changed"); emit_signal("tree_changed");
} }
void AnimationNodeBlendSpace2D::set_blend_mode(BlendMode p_blend_mode) {
blend_mode = p_blend_mode;
}
AnimationNodeBlendSpace2D::BlendMode AnimationNodeBlendSpace2D::get_blend_mode() const {
return blend_mode;
}
void AnimationNodeBlendSpace2D::_bind_methods() { 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"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1));
@ -565,6 +621,9 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_auto_triangles", "enable"), &AnimationNodeBlendSpace2D::set_auto_triangles); ClassDB::bind_method(D_METHOD("set_auto_triangles", "enable"), &AnimationNodeBlendSpace2D::set_auto_triangles);
ClassDB::bind_method(D_METHOD("get_auto_triangles"), &AnimationNodeBlendSpace2D::get_auto_triangles); ClassDB::bind_method(D_METHOD("get_auto_triangles"), &AnimationNodeBlendSpace2D::get_auto_triangles);
ClassDB::bind_method(D_METHOD("set_blend_mode", "mode"), &AnimationNodeBlendSpace2D::set_blend_mode);
ClassDB::bind_method(D_METHOD("get_blend_mode"), &AnimationNodeBlendSpace2D::get_blend_mode);
ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace2D::_tree_changed); ClassDB::bind_method(D_METHOD("_tree_changed"), &AnimationNodeBlendSpace2D::_tree_changed);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_auto_triangles", "get_auto_triangles"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_auto_triangles", "get_auto_triangles");
@ -581,6 +640,11 @@ void AnimationNodeBlendSpace2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "x_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_x_label", "get_x_label"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "x_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_x_label", "get_x_label");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_y_label", "get_y_label"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "y_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_y_label", "get_y_label");
ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_mode", PROPERTY_HINT_ENUM, "Interpolated,Discrete,Carry", PROPERTY_USAGE_NOEDITOR), "set_blend_mode", "get_blend_mode");
BIND_ENUM_CONSTANT(BLEND_MODE_INTERPOLATED);
BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE);
BIND_ENUM_CONSTANT(BLEND_MODE_DISCRETE_CARRY);
} }
AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() { AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() {
@ -597,6 +661,9 @@ AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() {
y_label = "y"; y_label = "y";
trianges_dirty = false; trianges_dirty = false;
blend_position = "blend_position"; blend_position = "blend_position";
closest = "closest";
length_internal = "length_internal";
blend_mode = BLEND_MODE_INTERPOLATED;
} }
AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() { AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() {

View file

@ -35,7 +35,14 @@
class AnimationNodeBlendSpace2D : public AnimationRootNode { class AnimationNodeBlendSpace2D : public AnimationRootNode {
GDCLASS(AnimationNodeBlendSpace2D, AnimationRootNode) GDCLASS(AnimationNodeBlendSpace2D, AnimationRootNode)
public:
enum BlendMode {
BLEND_MODE_INTERPOLATED,
BLEND_MODE_DISCRETE,
BLEND_MODE_DISCRETE_CARRY,
};
protected:
enum { enum {
MAX_BLEND_POINTS = 64 MAX_BLEND_POINTS = 64
}; };
@ -56,11 +63,14 @@ class AnimationNodeBlendSpace2D : public AnimationRootNode {
Vector<BlendTriangle> triangles; Vector<BlendTriangle> triangles;
StringName blend_position; StringName blend_position;
StringName closest;
StringName length_internal;
Vector2 max_space; Vector2 max_space;
Vector2 min_space; Vector2 min_space;
Vector2 snap; Vector2 snap;
String x_label; String x_label;
String y_label; String y_label;
BlendMode blend_mode;
void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node); void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node);
void _set_triangles(const Vector<int> &p_triangles); void _set_triangles(const Vector<int> &p_triangles);
@ -122,10 +132,15 @@ public:
void set_auto_triangles(bool p_enable); void set_auto_triangles(bool p_enable);
bool get_auto_triangles() const; bool get_auto_triangles() const;
void set_blend_mode(BlendMode p_blend_mode);
BlendMode get_blend_mode() const;
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name); virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
AnimationNodeBlendSpace2D(); AnimationNodeBlendSpace2D();
~AnimationNodeBlendSpace2D(); ~AnimationNodeBlendSpace2D();
}; };
VARIANT_ENUM_CAST(AnimationNodeBlendSpace2D::BlendMode)
#endif // ANIMATION_BLEND_SPACE_2D_H #endif // ANIMATION_BLEND_SPACE_2D_H