Forráskód Böngészése

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

Juan Linietsky 6 éve
szülő
commit
9018e8b132

+ 15 - 0
editor/plugins/animation_blend_space_2d_editor.cpp

@@ -607,6 +607,8 @@ void AnimationNodeBlendSpace2DEditor::_update_space() {
 
 	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_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_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_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();
@@ -752,6 +756,10 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) {
 		snap->set_icon(get_icon("SnapGrid", "EditorIcons"));
 		open_editor->set_icon(get_icon("Edit", "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) {
@@ -914,6 +922,13 @@ AnimationNodeBlendSpace2DEditor::AnimationNodeBlendSpace2DEditor() {
 	snap_y->set_step(0.01);
 	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);
 	top_hb->add_child(edit_hb);
 	edit_hb->add_child(memnew(VSeparator));

+ 1 - 0
editor/plugins/animation_blend_space_2d_editor.h

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

+ 126 - 59
scene/animation/animation_blend_space_2d.cpp

@@ -33,9 +33,17 @@
 
 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::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 {
-	return Vector2();
+	if (p_parameter == closest) {
+		return -1;
+	} else if (p_parameter == length_internal) {
+		return 0;
+	} else {
+		return Vector2();
+	}
 }
 
 void AnimationNodeBlendSpace2D::get_child_nodes(List<ChildNode> *r_child_nodes) {
@@ -412,84 +420,124 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) {
 	_update_triangles();
 
 	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 (triangles.size() == 0)
-		return 0;
+	if (blend_mode == BLEND_MODE_INTERPOLATED) {
 
-	Vector2 best_point;
-	bool first = true;
-	int blend_triangle = -1;
-	float blend_weights[3] = { 0, 0, 0 };
+		if (triangles.size() == 0)
+			return 0;
 
-	for (int i = 0; i < triangles.size(); i++) {
-		Vector2 points[3];
-		for (int j = 0; j < 3; j++) {
-			points[j] = get_blend_point_position(get_triangle_point(i, j));
-		}
+		Vector2 best_point;
+		bool first = true;
+		int blend_triangle = -1;
+		float blend_weights[3] = { 0, 0, 0 };
 
-		if (Geometry::is_point_in_triangle(blend_pos, points[0], points[1], points[2])) {
+		for (int i = 0; i < triangles.size(); i++) {
+			Vector2 points[3];
+			for (int j = 0; j < 3; j++) {
+				points[j] = get_blend_point_position(get_triangle_point(i, j));
+			}
 
-			blend_triangle = i;
-			_blend_triangle(blend_pos, points, blend_weights);
-			break;
-		}
+			if (Geometry::is_point_in_triangle(blend_pos, points[0], points[1], points[2])) {
 
-		for (int j = 0; j < 3; j++) {
-			Vector2 s[2] = {
-				points[j],
-				points[(j + 1) % 3]
-			};
-			Vector2 closest = Geometry::get_closest_point_to_segment_2d(blend_pos, s);
-			if (first || closest.distance_to(blend_pos) < best_point.distance_to(blend_pos)) {
-				best_point = closest;
 				blend_triangle = i;
-				first = false;
-				float d = s[0].distance_to(s[1]);
-				if (d == 0.0) {
-					blend_weights[j] = 1.0;
-					blend_weights[(j + 1) % 3] = 0.0;
-					blend_weights[(j + 2) % 3] = 0.0;
-				} else {
-					float c = s[0].distance_to(closest) / d;
-
-					blend_weights[j] = 1.0 - c;
-					blend_weights[(j + 1) % 3] = c;
-					blend_weights[(j + 2) % 3] = 0.0;
+				_blend_triangle(blend_pos, points, blend_weights);
+				break;
+			}
+
+			for (int j = 0; j < 3; j++) {
+				Vector2 s[2] = {
+					points[j],
+					points[(j + 1) % 3]
+				};
+				Vector2 closest = Geometry::get_closest_point_to_segment_2d(blend_pos, s);
+				if (first || closest.distance_to(blend_pos) < best_point.distance_to(blend_pos)) {
+					best_point = closest;
+					blend_triangle = i;
+					first = false;
+					float d = s[0].distance_to(s[1]);
+					if (d == 0.0) {
+						blend_weights[j] = 1.0;
+						blend_weights[(j + 1) % 3] = 0.0;
+						blend_weights[(j + 2) % 3] = 0.0;
+					} else {
+						float c = s[0].distance_to(closest) / d;
+
+						blend_weights[j] = 1.0 - c;
+						blend_weights[(j + 1) % 3] = c;
+						blend_weights[(j + 2) % 3] = 0.0;
+					}
 				}
 			}
 		}
-	}
 
-	ERR_FAIL_COND_V(blend_triangle == -1, 0); //should never reach here
+		ERR_FAIL_COND_V(blend_triangle == -1, 0); //should never reach here
 
-	int triangle_points[3];
-	for (int j = 0; j < 3; j++) {
-		triangle_points[j] = get_triangle_point(blend_triangle, j);
-	}
+		int triangle_points[3];
+		for (int j = 0; j < 3; j++) {
+			triangle_points[j] = get_triangle_point(blend_triangle, j);
+		}
 
-	first = true;
-	float mind = 0;
-	for (int i = 0; i < blend_points_used; i++) {
+		first = true;
 
-		bool found = false;
-		for (int j = 0; j < 3; j++) {
-			if (i == triangle_points[j]) {
-				//blend with the given weight
-				float t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false);
-				if (first || t < mind) {
-					mind = t;
-					first = false;
+		for (int i = 0; i < blend_points_used; i++) {
+
+			bool found = false;
+			for (int j = 0; j < 3; j++) {
+				if (i == triangle_points[j]) {
+					//blend with the given weight
+					float t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, blend_weights[j], FILTER_IGNORE, false);
+					if (first || t < mind) {
+						mind = t;
+						first = false;
+					}
+					found = true;
+					break;
 				}
-				found = true;
-				break;
+			}
+
+			if (!found) {
+				//ignore
+				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 (!found) {
-			//ignore
-			blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, 0, FILTER_IGNORE, false);
+		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;
 }
 
@@ -527,6 +575,14 @@ void AnimationNodeBlendSpace2D::_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() {
 
 	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("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);
 
 	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::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::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() {
@@ -597,6 +661,9 @@ AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() {
 	y_label = "y";
 	trianges_dirty = false;
 	blend_position = "blend_position";
+	closest = "closest";
+	length_internal = "length_internal";
+	blend_mode = BLEND_MODE_INTERPOLATED;
 }
 
 AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() {

+ 15 - 0
scene/animation/animation_blend_space_2d.h

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