diff options
Diffstat (limited to 'scene/animation')
-rw-r--r-- | scene/animation/animation_blend_space_1d.cpp | 284 | ||||
-rw-r--r-- | scene/animation/animation_blend_space_1d.h | 68 | ||||
-rw-r--r-- | scene/animation/animation_blend_space_2d.cpp (renamed from scene/animation/animation_blend_space.cpp) | 150 | ||||
-rw-r--r-- | scene/animation/animation_blend_space_2d.h (renamed from scene/animation/animation_blend_space.h) | 24 | ||||
-rw-r--r-- | scene/animation/animation_blend_tree.cpp | 16 | ||||
-rw-r--r-- | scene/animation/animation_blend_tree.h | 4 | ||||
-rw-r--r-- | scene/animation/animation_node_state_machine.cpp | 790 | ||||
-rw-r--r-- | scene/animation/animation_node_state_machine.h | 142 | ||||
-rw-r--r-- | scene/animation/animation_tree.cpp (renamed from scene/animation/animation_graph_player.cpp) | 88 | ||||
-rw-r--r-- | scene/animation/animation_tree.h (renamed from scene/animation/animation_graph_player.h) | 20 |
10 files changed, 1435 insertions, 151 deletions
diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp new file mode 100644 index 0000000000..6993c0a785 --- /dev/null +++ b/scene/animation/animation_blend_space_1d.cpp @@ -0,0 +1,284 @@ +#include "animation_blend_space_1d.h" + +void AnimationNodeBlendSpace1D::_validate_property(PropertyInfo &property) const { + if (property.name.begins_with("blend_point_")) { + String left = property.name.get_slicec('/', 0); + int idx = left.get_slicec('_', 2).to_int(); + if (idx >= blend_points_used) { + property.usage = 0; + } + } + AnimationRootNode::_validate_property(property); +} + +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("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("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("set_min_space", "min_space"), &AnimationNodeBlendSpace1D::set_min_space); + ClassDB::bind_method(D_METHOD("get_min_space"), &AnimationNodeBlendSpace1D::get_min_space); + + ClassDB::bind_method(D_METHOD("set_max_space", "max_space"), &AnimationNodeBlendSpace1D::set_max_space); + ClassDB::bind_method(D_METHOD("get_max_space"), &AnimationNodeBlendSpace1D::get_max_space); + + ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace1D::set_snap); + ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace1D::get_snap); + + ClassDB::bind_method(D_METHOD("set_blend_pos", "pos"), &AnimationNodeBlendSpace1D::set_blend_pos); + ClassDB::bind_method(D_METHOD("get_blend_pos"), &AnimationNodeBlendSpace1D::get_blend_pos); + + 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("_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", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "_add_blend_point", "get_blend_point_node", i); + ADD_PROPERTYI(PropertyInfo(Variant::REAL, "blend_point_" + itos(i) + "/pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_blend_point_position", "get_blend_point_position", i); + } + + ADD_PROPERTY(PropertyInfo(Variant::REAL, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_min_space", "get_min_space"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_space", "get_max_space"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "blend_pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_blend_pos", "get_blend_pos"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "value_label", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_value_label", "get_value_label"); +} + +void AnimationNodeBlendSpace1D::add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index) { + ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS); + ERR_FAIL_COND(p_node.is_null()); + ERR_FAIL_COND(p_node->get_parent().is_valid()); + ERR_FAIL_COND(p_at_index < -1 || p_at_index > blend_points_used); + + if (p_at_index == -1 || p_at_index == blend_points_used) { + p_at_index = blend_points_used; + } else { + for (int i = blend_points_used - 1; i > p_at_index; i++) { + blend_points[i] = blend_points[i - 1]; + } + } + + blend_points[p_at_index].node = p_node; + blend_points[p_at_index].position = p_position; + + blend_points[p_at_index].node->set_parent(this); + blend_points[p_at_index].node->set_tree(get_tree()); + + blend_points_used++; +} + +void AnimationNodeBlendSpace1D::set_blend_point_position(int p_point, float p_position) { + ERR_FAIL_INDEX(p_point, blend_points_used); + + blend_points[p_point].position = p_position; +} + +void AnimationNodeBlendSpace1D::set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node) { + ERR_FAIL_INDEX(p_point, blend_points_used); + ERR_FAIL_COND(p_node.is_null()); + + if (blend_points[p_point].node.is_valid()) { + blend_points[p_point].node->set_parent(NULL); + blend_points[p_point].node->set_tree(NULL); + } + + blend_points[p_point].node = p_node; + blend_points[p_point].node->set_parent(this); + blend_points[p_point].node->set_tree(get_tree()); +} + +float AnimationNodeBlendSpace1D::get_blend_point_position(int p_point) const { + ERR_FAIL_INDEX_V(p_point, blend_points_used, 0); + return blend_points[p_point].position; +} + +Ref<AnimationRootNode> AnimationNodeBlendSpace1D::get_blend_point_node(int p_point) const { + ERR_FAIL_INDEX_V(p_point, blend_points_used, Ref<AnimationRootNode>()); + return blend_points[p_point].node; +} + +void AnimationNodeBlendSpace1D::remove_blend_point(int p_point) { + ERR_FAIL_INDEX(p_point, blend_points_used); + + blend_points[p_point].node->set_parent(NULL); + blend_points[p_point].node->set_tree(NULL); + + for (int i = p_point; i < blend_points_used - 1; i++) { + blend_points[i] = blend_points[i + 1]; + } + + blend_points_used--; +} + +int AnimationNodeBlendSpace1D::get_blend_point_count() const { + + return blend_points_used; +} + +void AnimationNodeBlendSpace1D::set_min_space(float p_min) { + min_space = p_min; + + if (min_space >= max_space) { + min_space = max_space - 1; + } +} + +float AnimationNodeBlendSpace1D::get_min_space() const { + return min_space; +} + +void AnimationNodeBlendSpace1D::set_max_space(float p_max) { + max_space = p_max; + + if (max_space <= min_space) { + max_space = min_space + 1; + } +} + +float AnimationNodeBlendSpace1D::get_max_space() const { + return max_space; +} + +void AnimationNodeBlendSpace1D::set_snap(float p_snap) { + snap = p_snap; +} + +float AnimationNodeBlendSpace1D::get_snap() const { + return snap; +} + +void AnimationNodeBlendSpace1D::set_blend_pos(float p_pos) { + blend_pos = p_pos; +} + +float AnimationNodeBlendSpace1D::get_blend_pos() const { + return blend_pos; +} + +void AnimationNodeBlendSpace1D::set_value_label(const String &p_label) { + value_label = p_label; +} + +String AnimationNodeBlendSpace1D::get_value_label() const { + return value_label; +} + +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); + } +} + +float AnimationNodeBlendSpace1D::process(float p_time, bool p_seek) { + + if (blend_points_used == 0) { + return 0.0; + } + + if (blend_points_used == 1) { + // only one point available, just play that animation + return blend_node(blend_points[0].node, p_time, p_seek, 1.0, FILTER_IGNORE, false); + } + + 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) { + // 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 + + float max_time_remaining = 0.0; + + for (int i = 0; i < blend_points_used; i++) { + float remaining = blend_node(blend_points[i].node, p_time, p_seek, weights[i], FILTER_IGNORE, false); + + max_time_remaining = MAX(max_time_remaining, remaining); + } + + return max_time_remaining; +} + +String AnimationNodeBlendSpace1D::get_caption() const { + return "BlendSpace1D"; +} + +AnimationNodeBlendSpace1D::AnimationNodeBlendSpace1D() { + + blend_points_used = 0; + max_space = 1; + min_space = -1; + + snap = 0.1; + value_label = "value"; +} + +AnimationNodeBlendSpace1D::~AnimationNodeBlendSpace1D() { + + for (int i = 0; i < blend_points_used; i++) { + blend_points[i].node->set_parent(this); + blend_points[i].node->set_tree(get_tree()); + } +} diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h new file mode 100644 index 0000000000..6e264076c4 --- /dev/null +++ b/scene/animation/animation_blend_space_1d.h @@ -0,0 +1,68 @@ +#ifndef ANIMATION_BLEND_SPACE_1D_H +#define ANIMATION_BLEND_SPACE_1D_H + +#include "scene/animation/animation_tree.h" + +class AnimationNodeBlendSpace1D : public AnimationRootNode { + GDCLASS(AnimationNodeBlendSpace1D, AnimationRootNode) + + enum { + MAX_BLEND_POINTS = 64 + }; + + struct BlendPoint { + Ref<AnimationRootNode> node; + float position; + }; + + BlendPoint blend_points[MAX_BLEND_POINTS]; + int blend_points_used; + + float blend_pos; + + float max_space; + float min_space; + + float snap; + + String value_label; + + void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node); + +protected: + virtual void _validate_property(PropertyInfo &property) const; + static void _bind_methods(); + +public: + void add_blend_point(const Ref<AnimationRootNode> &p_node, float p_position, int p_at_index = -1); + 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 remove_blend_point(int p_point); + int get_blend_point_count() const; + + void set_min_space(float p_min); + float get_min_space() const; + + void set_max_space(float p_max); + float get_max_space() const; + + void set_snap(float p_snap); + float get_snap() const; + + void set_blend_pos(float p_pos); + float get_blend_pos() const; + + void set_value_label(const String &p_label); + String get_value_label() const; + + float process(float p_time, bool p_seek); + String get_caption() const; + + AnimationNodeBlendSpace1D(); + ~AnimationNodeBlendSpace1D(); +}; + +#endif // ANIMATION_BLEND_SPACE_1D_H diff --git a/scene/animation/animation_blend_space.cpp b/scene/animation/animation_blend_space_2d.cpp index 44b2d980e2..28e4ca4eda 100644 --- a/scene/animation/animation_blend_space.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -1,7 +1,7 @@ -#include "animation_blend_space.h" +#include "animation_blend_space_2d.h" #include "math/delaunay.h" -void AnimationNodeBlendSpace::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) { ERR_FAIL_COND(blend_points_used >= MAX_BLEND_POINTS); ERR_FAIL_COND(p_node.is_null()); ERR_FAIL_COND(p_node->get_parent().is_valid()); @@ -10,7 +10,7 @@ void AnimationNodeBlendSpace::add_blend_point(const Ref<AnimationRootNode> &p_no if (p_at_index == -1 || p_at_index == blend_points_used) { p_at_index = blend_points_used; } else { - for (int i = blend_points_used; i > p_at_index; i--) { + for (int i = blend_points_used - 1; i > p_at_index; i--) { blend_points[i] = blend_points[i - 1]; } for (int i = 0; i < triangles.size(); i++) { @@ -25,7 +25,7 @@ void AnimationNodeBlendSpace::add_blend_point(const Ref<AnimationRootNode> &p_no blend_points[p_at_index].position = p_position; blend_points[p_at_index].node->set_parent(this); - blend_points[p_at_index].node->set_graph_player(get_graph_player()); + blend_points[p_at_index].node->set_tree(get_tree()); blend_points_used++; if (auto_triangles) { @@ -33,38 +33,38 @@ void AnimationNodeBlendSpace::add_blend_point(const Ref<AnimationRootNode> &p_no } } -void AnimationNodeBlendSpace::set_blend_point_position(int p_point, const Vector2 &p_position) { +void AnimationNodeBlendSpace2D::set_blend_point_position(int p_point, const Vector2 &p_position) { ERR_FAIL_INDEX(p_point, blend_points_used); blend_points[p_point].position = p_position; if (auto_triangles) { trianges_dirty = true; } } -void AnimationNodeBlendSpace::set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node) { +void AnimationNodeBlendSpace2D::set_blend_point_node(int p_point, const Ref<AnimationRootNode> &p_node) { ERR_FAIL_INDEX(p_point, blend_points_used); ERR_FAIL_COND(p_node.is_null()); if (blend_points[p_point].node.is_valid()) { blend_points[p_point].node->set_parent(NULL); - blend_points[p_point].node->set_graph_player(NULL); + blend_points[p_point].node->set_tree(NULL); } blend_points[p_point].node = p_node; blend_points[p_point].node->set_parent(this); - blend_points[p_point].node->set_graph_player(get_graph_player()); + blend_points[p_point].node->set_tree(get_tree()); } -Vector2 AnimationNodeBlendSpace::get_blend_point_position(int p_point) const { +Vector2 AnimationNodeBlendSpace2D::get_blend_point_position(int p_point) const { ERR_FAIL_INDEX_V(p_point, blend_points_used, Vector2()); return blend_points[p_point].position; } -Ref<AnimationRootNode> AnimationNodeBlendSpace::get_blend_point_node(int p_point) const { +Ref<AnimationRootNode> AnimationNodeBlendSpace2D::get_blend_point_node(int p_point) const { ERR_FAIL_INDEX_V(p_point, blend_points_used, Ref<AnimationRootNode>()); return blend_points[p_point].node; } -void AnimationNodeBlendSpace::remove_blend_point(int p_point) { +void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) { ERR_FAIL_INDEX(p_point, blend_points_used); blend_points[p_point].node->set_parent(NULL); - blend_points[p_point].node->set_graph_player(NULL); + blend_points[p_point].node->set_tree(NULL); for (int i = 0; i < triangles.size(); i++) { bool erase = false; @@ -89,12 +89,12 @@ void AnimationNodeBlendSpace::remove_blend_point(int p_point) { blend_points_used--; } -int AnimationNodeBlendSpace::get_blend_point_count() const { +int AnimationNodeBlendSpace2D::get_blend_point_count() const { return blend_points_used; } -bool AnimationNodeBlendSpace::has_triangle(int p_x, int p_y, int p_z) const { +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); @@ -123,7 +123,7 @@ bool AnimationNodeBlendSpace::has_triangle(int p_x, int p_y, int p_z) const { return false; } -void AnimationNodeBlendSpace::add_triangle(int p_x, int p_y, int p_z, int p_at_index) { +void AnimationNodeBlendSpace2D::add_triangle(int p_x, int p_y, int p_z, int p_at_index) { ERR_FAIL_INDEX(p_x, blend_points_used); ERR_FAIL_INDEX(p_y, blend_points_used); @@ -156,7 +156,7 @@ void AnimationNodeBlendSpace::add_triangle(int p_x, int p_y, int p_z, int p_at_i triangles.insert(p_at_index, t); } } -int AnimationNodeBlendSpace::get_triangle_point(int p_triangle, int p_point) { +int AnimationNodeBlendSpace2D::get_triangle_point(int p_triangle, int p_point) { _update_triangles(); @@ -164,17 +164,17 @@ int AnimationNodeBlendSpace::get_triangle_point(int p_triangle, int p_point) { ERR_FAIL_INDEX_V(p_triangle, triangles.size(), -1); return triangles[p_triangle].points[p_point]; } -void AnimationNodeBlendSpace::remove_triangle(int p_triangle) { +void AnimationNodeBlendSpace2D::remove_triangle(int p_triangle) { ERR_FAIL_INDEX(p_triangle, triangles.size()); triangles.remove(p_triangle); } -int AnimationNodeBlendSpace::get_triangle_count() const { +int AnimationNodeBlendSpace2D::get_triangle_count() const { return triangles.size(); } -void AnimationNodeBlendSpace::set_min_space(const Vector2 &p_min) { +void AnimationNodeBlendSpace2D::set_min_space(const Vector2 &p_min) { min_space = p_min; if (min_space.x >= max_space.x) { @@ -184,11 +184,11 @@ void AnimationNodeBlendSpace::set_min_space(const Vector2 &p_min) { min_space.y = max_space.y - 1; } } -Vector2 AnimationNodeBlendSpace::get_min_space() const { +Vector2 AnimationNodeBlendSpace2D::get_min_space() const { return min_space; } -void AnimationNodeBlendSpace::set_max_space(const Vector2 &p_max) { +void AnimationNodeBlendSpace2D::set_max_space(const Vector2 &p_max) { max_space = p_max; if (max_space.x <= min_space.x) { @@ -198,39 +198,39 @@ void AnimationNodeBlendSpace::set_max_space(const Vector2 &p_max) { max_space.y = min_space.y + 1; } } -Vector2 AnimationNodeBlendSpace::get_max_space() const { +Vector2 AnimationNodeBlendSpace2D::get_max_space() const { return max_space; } -void AnimationNodeBlendSpace::set_snap(const Vector2 &p_snap) { +void AnimationNodeBlendSpace2D::set_snap(const Vector2 &p_snap) { snap = p_snap; } -Vector2 AnimationNodeBlendSpace::get_snap() const { +Vector2 AnimationNodeBlendSpace2D::get_snap() const { return snap; } -void AnimationNodeBlendSpace::set_blend_pos(const Vector2 &p_pos) { +void AnimationNodeBlendSpace2D::set_blend_position(const Vector2 &p_pos) { blend_pos = p_pos; } -Vector2 AnimationNodeBlendSpace::get_blend_pos() const { +Vector2 AnimationNodeBlendSpace2D::get_blend_position() const { return blend_pos; } -void AnimationNodeBlendSpace::set_x_label(const String &p_label) { +void AnimationNodeBlendSpace2D::set_x_label(const String &p_label) { x_label = p_label; } -String AnimationNodeBlendSpace::get_x_label() const { +String AnimationNodeBlendSpace2D::get_x_label() const { return x_label; } -void AnimationNodeBlendSpace::set_y_label(const String &p_label) { +void AnimationNodeBlendSpace2D::set_y_label(const String &p_label) { y_label = p_label; } -String AnimationNodeBlendSpace::get_y_label() const { +String AnimationNodeBlendSpace2D::get_y_label() const { return y_label; } -void AnimationNodeBlendSpace::_add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node) { +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 { @@ -238,7 +238,7 @@ void AnimationNodeBlendSpace::_add_blend_point(int p_index, const Ref<AnimationR } } -void AnimationNodeBlendSpace::_set_triangles(const Vector<int> &p_triangles) { +void AnimationNodeBlendSpace2D::_set_triangles(const Vector<int> &p_triangles) { if (auto_triangles) return; @@ -248,7 +248,7 @@ void AnimationNodeBlendSpace::_set_triangles(const Vector<int> &p_triangles) { } } -Vector<int> AnimationNodeBlendSpace::_get_triangles() const { +Vector<int> AnimationNodeBlendSpace2D::_get_triangles() const { Vector<int> t; if (auto_triangles && trianges_dirty) @@ -263,7 +263,7 @@ Vector<int> AnimationNodeBlendSpace::_get_triangles() const { return t; } -void AnimationNodeBlendSpace::_update_triangles() { +void AnimationNodeBlendSpace2D::_update_triangles() { if (!auto_triangles || !trianges_dirty) return; @@ -286,7 +286,7 @@ void AnimationNodeBlendSpace::_update_triangles() { } } -Vector2 AnimationNodeBlendSpace::get_closest_point(const Vector2 &p_point) { +Vector2 AnimationNodeBlendSpace2D::get_closest_point(const Vector2 &p_point) { _update_triangles(); @@ -323,7 +323,7 @@ Vector2 AnimationNodeBlendSpace::get_closest_point(const Vector2 &p_point) { return best_point; } -void AnimationNodeBlendSpace::_blend_triangle(const Vector2 &p_pos, const Vector2 *p_points, float *r_weights) { +void AnimationNodeBlendSpace2D::_blend_triangle(const Vector2 &p_pos, const Vector2 *p_points, float *r_weights) { if (p_pos.distance_squared_to(p_points[0]) < CMP_EPSILON2) { r_weights[0] = 1; @@ -369,7 +369,7 @@ void AnimationNodeBlendSpace::_blend_triangle(const Vector2 &p_pos, const Vector r_weights[2] = w; } -float AnimationNodeBlendSpace::process(float p_time, bool p_seek) { +float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { _update_triangles(); @@ -453,11 +453,11 @@ float AnimationNodeBlendSpace::process(float p_time, bool p_seek) { return mind; } -String AnimationNodeBlendSpace::get_caption() const { - return "BlendSpace"; +String AnimationNodeBlendSpace2D::get_caption() const { + return "BlendSpace2D"; } -void AnimationNodeBlendSpace::_validate_property(PropertyInfo &property) const { +void AnimationNodeBlendSpace2D::_validate_property(PropertyInfo &property) const { if (property.name.begins_with("blend_point_")) { String left = property.name.get_slicec('/', 0); int idx = left.get_slicec('_', 2).to_int(); @@ -468,57 +468,57 @@ void AnimationNodeBlendSpace::_validate_property(PropertyInfo &property) const { AnimationRootNode::_validate_property(property); } -void AnimationNodeBlendSpace::set_auto_triangles(bool p_enable) { +void AnimationNodeBlendSpace2D::set_auto_triangles(bool p_enable) { auto_triangles = p_enable; if (auto_triangles) { trianges_dirty = true; } } -bool AnimationNodeBlendSpace::get_auto_triangles() const { +bool AnimationNodeBlendSpace2D::get_auto_triangles() const { return auto_triangles; } -void AnimationNodeBlendSpace::_bind_methods() { +void AnimationNodeBlendSpace2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace::add_blend_point, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("set_blend_point_position", "point", "pos"), &AnimationNodeBlendSpace::set_blend_point_position); - ClassDB::bind_method(D_METHOD("get_blend_point_position", "point"), &AnimationNodeBlendSpace::get_blend_point_position); - ClassDB::bind_method(D_METHOD("set_blend_point_node", "point", "node"), &AnimationNodeBlendSpace::set_blend_point_node); - ClassDB::bind_method(D_METHOD("get_blend_point_node", "point"), &AnimationNodeBlendSpace::get_blend_point_node); - ClassDB::bind_method(D_METHOD("remove_blend_point", "point"), &AnimationNodeBlendSpace::remove_blend_point); - ClassDB::bind_method(D_METHOD("get_blend_point_count"), &AnimationNodeBlendSpace::get_blend_point_count); + ClassDB::bind_method(D_METHOD("add_blend_point", "node", "pos", "at_index"), &AnimationNodeBlendSpace2D::add_blend_point, DEFVAL(-1)); + 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("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("add_triangle", "x", "y", "z", "at_index"), &AnimationNodeBlendSpace::add_triangle, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("get_triangle_point", "triangle", "point"), &AnimationNodeBlendSpace::get_triangle_point); - ClassDB::bind_method(D_METHOD("remove_triangle", "triangle"), &AnimationNodeBlendSpace::remove_triangle); - ClassDB::bind_method(D_METHOD("get_triangle_count"), &AnimationNodeBlendSpace::get_triangle_count); + 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); + ClassDB::bind_method(D_METHOD("remove_triangle", "triangle"), &AnimationNodeBlendSpace2D::remove_triangle); + ClassDB::bind_method(D_METHOD("get_triangle_count"), &AnimationNodeBlendSpace2D::get_triangle_count); - ClassDB::bind_method(D_METHOD("set_min_space", "min_space"), &AnimationNodeBlendSpace::set_min_space); - ClassDB::bind_method(D_METHOD("get_min_space"), &AnimationNodeBlendSpace::get_min_space); + ClassDB::bind_method(D_METHOD("set_min_space", "min_space"), &AnimationNodeBlendSpace2D::set_min_space); + ClassDB::bind_method(D_METHOD("get_min_space"), &AnimationNodeBlendSpace2D::get_min_space); - ClassDB::bind_method(D_METHOD("set_max_space", "max_space"), &AnimationNodeBlendSpace::set_max_space); - ClassDB::bind_method(D_METHOD("get_max_space"), &AnimationNodeBlendSpace::get_max_space); + ClassDB::bind_method(D_METHOD("set_max_space", "max_space"), &AnimationNodeBlendSpace2D::set_max_space); + ClassDB::bind_method(D_METHOD("get_max_space"), &AnimationNodeBlendSpace2D::get_max_space); - ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace::set_snap); - ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace::get_snap); + ClassDB::bind_method(D_METHOD("set_snap", "snap"), &AnimationNodeBlendSpace2D::set_snap); + ClassDB::bind_method(D_METHOD("get_snap"), &AnimationNodeBlendSpace2D::get_snap); - ClassDB::bind_method(D_METHOD("set_blend_pos", "pos"), &AnimationNodeBlendSpace::set_blend_pos); - ClassDB::bind_method(D_METHOD("get_blend_pos"), &AnimationNodeBlendSpace::get_blend_pos); + ClassDB::bind_method(D_METHOD("set_blend_position", "pos"), &AnimationNodeBlendSpace2D::set_blend_position); + ClassDB::bind_method(D_METHOD("get_blend_position"), &AnimationNodeBlendSpace2D::get_blend_position); - ClassDB::bind_method(D_METHOD("set_x_label", "text"), &AnimationNodeBlendSpace::set_x_label); - ClassDB::bind_method(D_METHOD("get_x_label"), &AnimationNodeBlendSpace::get_x_label); + ClassDB::bind_method(D_METHOD("set_x_label", "text"), &AnimationNodeBlendSpace2D::set_x_label); + ClassDB::bind_method(D_METHOD("get_x_label"), &AnimationNodeBlendSpace2D::get_x_label); - ClassDB::bind_method(D_METHOD("set_y_label", "text"), &AnimationNodeBlendSpace::set_y_label); - ClassDB::bind_method(D_METHOD("get_y_label"), &AnimationNodeBlendSpace::get_y_label); + 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"), &AnimationNodeBlendSpace::_add_blend_point); + ClassDB::bind_method(D_METHOD("_add_blend_point", "index", "node"), &AnimationNodeBlendSpace2D::_add_blend_point); - ClassDB::bind_method(D_METHOD("_set_triangles", "triangles"), &AnimationNodeBlendSpace::_set_triangles); - ClassDB::bind_method(D_METHOD("_get_triangles"), &AnimationNodeBlendSpace::_get_triangles); + ClassDB::bind_method(D_METHOD("_set_triangles", "triangles"), &AnimationNodeBlendSpace2D::_set_triangles); + ClassDB::bind_method(D_METHOD("_get_triangles"), &AnimationNodeBlendSpace2D::_get_triangles); - ClassDB::bind_method(D_METHOD("set_auto_triangles", "enable"), &AnimationNodeBlendSpace::set_auto_triangles); - ClassDB::bind_method(D_METHOD("get_auto_triangles"), &AnimationNodeBlendSpace::get_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); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_triangles", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_auto_triangles", "get_auto_triangles"); @@ -532,12 +532,12 @@ void AnimationNodeBlendSpace::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "min_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_min_space", "get_min_space"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "max_space", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_max_space", "get_max_space"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "snap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_snap", "get_snap"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "blend_pos", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_blend_pos", "get_blend_pos"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "blend_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_blend_position", "get_blend_position"); 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"); } -AnimationNodeBlendSpace::AnimationNodeBlendSpace() { +AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() { auto_triangles = true; blend_points_used = 0; @@ -549,10 +549,10 @@ AnimationNodeBlendSpace::AnimationNodeBlendSpace() { trianges_dirty = false; } -AnimationNodeBlendSpace::~AnimationNodeBlendSpace() { +AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() { for (int i = 0; i < blend_points_used; i++) { blend_points[i].node->set_parent(this); - blend_points[i].node->set_graph_player(get_graph_player()); + blend_points[i].node->set_tree(get_tree()); } } diff --git a/scene/animation/animation_blend_space.h b/scene/animation/animation_blend_space_2d.h index 3eda3d2d39..5af0b9ba7f 100644 --- a/scene/animation/animation_blend_space.h +++ b/scene/animation/animation_blend_space_2d.h @@ -1,10 +1,10 @@ -#ifndef ANIMATION_BLEND_SPACE_H -#define ANIMATION_BLEND_SPACE_H +#ifndef ANIMATION_BLEND_SPACE_2D_H +#define ANIMATION_BLEND_SPACE_2D_H -#include "scene/animation/animation_graph_player.h" +#include "scene/animation/animation_tree.h" -class AnimationNodeBlendSpace : public AnimationRootNode { - GDCLASS(AnimationNodeBlendSpace, AnimationRootNode) +class AnimationNodeBlendSpace2D : public AnimationRootNode { + GDCLASS(AnimationNodeBlendSpace2D, AnimationRootNode) enum { MAX_BLEND_POINTS = 64 @@ -70,8 +70,8 @@ public: void set_snap(const Vector2 &p_snap); Vector2 get_snap() const; - void set_blend_pos(const Vector2 &p_pos); - Vector2 get_blend_pos() const; + void set_blend_position(const Vector2 &p_pos); + Vector2 get_blend_position() const; void set_x_label(const String &p_label); String get_x_label() const; @@ -79,16 +79,16 @@ public: void set_y_label(const String &p_label); String get_y_label() const; - float process(float p_time, bool p_seek); - String get_caption() const; + virtual float process(float p_time, bool p_seek); + virtual String get_caption() const; Vector2 get_closest_point(const Vector2 &p_point); void set_auto_triangles(bool p_enable); bool get_auto_triangles() const; - AnimationNodeBlendSpace(); - ~AnimationNodeBlendSpace(); + AnimationNodeBlendSpace2D(); + ~AnimationNodeBlendSpace2D(); }; -#endif // ANIMATION_BLEND_SPACE_H +#endif // ANIMATION_BLEND_SPACE_2D_H diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index ced0cbbbba..feacea5656 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -16,7 +16,7 @@ float AnimationNodeAnimation::get_playback_time() const { void AnimationNodeAnimation::_validate_property(PropertyInfo &property) const { if (property.name == "animation") { - AnimationGraphPlayer *gp = get_graph_player(); + AnimationTree *gp = get_tree(); if (gp && gp->has_node(gp->get_animation_player())) { AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); if (ap) { @@ -762,13 +762,13 @@ void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref<AnimationNod ERR_FAIL_COND(nodes.has(p_name)); ERR_FAIL_COND(p_node.is_null()); ERR_FAIL_COND(p_node->get_parent().is_valid()); - ERR_FAIL_COND(p_node->get_graph_player() != NULL); + ERR_FAIL_COND(p_node->get_tree() != NULL); ERR_FAIL_COND(p_name == SceneStringNames::get_singleton()->output); ERR_FAIL_COND(String(p_name).find("/") != -1); nodes[p_name] = p_node; p_node->set_parent(this); - p_node->set_graph_player(get_graph_player()); + p_node->set_tree(get_tree()); emit_changed(); } @@ -804,7 +804,7 @@ void AnimationNodeBlendTree::remove_node(const StringName &p_name) { node->set_input_connection(i, StringName()); } node->set_parent(NULL); - node->set_graph_player(NULL); + node->set_tree(NULL); } nodes.erase(p_name); @@ -965,13 +965,13 @@ Vector2 AnimationNodeBlendTree::get_graph_offset() const { return graph_offset; } -void AnimationNodeBlendTree::set_graph_player(AnimationGraphPlayer *p_player) { +void AnimationNodeBlendTree::set_tree(AnimationTree *p_player) { - AnimationNode::set_graph_player(p_player); + AnimationNode::set_tree(p_player); for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { Ref<AnimationNode> node = E->get(); - node->set_graph_player(p_player); + node->set_tree(p_player); } } @@ -1107,6 +1107,6 @@ AnimationNodeBlendTree::~AnimationNodeBlendTree() { for (Map<StringName, Ref<AnimationNode> >::Element *E = nodes.front(); E; E = E->next()) { E->get()->set_parent(NULL); - E->get()->set_graph_player(NULL); + E->get()->set_tree(NULL); } } diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index 7623fd3e57..8d7932196c 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -1,7 +1,7 @@ #ifndef ANIMATION_BLEND_TREE_H #define ANIMATION_BLEND_TREE_H -#include "scene/animation/animation_graph_player.h" +#include "scene/animation/animation_tree.h" class AnimationNodeAnimation : public AnimationRootNode { @@ -318,7 +318,7 @@ public: void set_graph_offset(const Vector2 &p_graph_offset); Vector2 get_graph_offset() const; - virtual void set_graph_player(AnimationGraphPlayer *p_player); + virtual void set_tree(AnimationTree *p_player); AnimationNodeBlendTree(); ~AnimationNodeBlendTree(); }; diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp new file mode 100644 index 0000000000..c5ad980806 --- /dev/null +++ b/scene/animation/animation_node_state_machine.cpp @@ -0,0 +1,790 @@ +#include "animation_node_state_machine.h" + +///////////////////////////////////////////////// + +void AnimationNodeStateMachineTransition::set_switch_mode(SwitchMode p_mode) { + + switch_mode = p_mode; +} + +AnimationNodeStateMachineTransition::SwitchMode AnimationNodeStateMachineTransition::get_switch_mode() const { + + return switch_mode; +} + +void AnimationNodeStateMachineTransition::set_auto_advance(bool p_enable) { + auto_advance = p_enable; +} + +bool AnimationNodeStateMachineTransition::has_auto_advance() const { + return auto_advance; +} + +void AnimationNodeStateMachineTransition::set_xfade_time(float p_xfade) { + + ERR_FAIL_COND(p_xfade < 0); + xfade = p_xfade; + emit_changed(); +} + +float AnimationNodeStateMachineTransition::get_xfade_time() const { + return xfade; +} + +void AnimationNodeStateMachineTransition::set_disabled(bool p_disabled) { + disabled = p_disabled; + emit_changed(); +} + +bool AnimationNodeStateMachineTransition::is_disabled() const { + return disabled; +} + +void AnimationNodeStateMachineTransition::set_priority(int p_priority) { + priority = p_priority; + emit_changed(); +} + +int AnimationNodeStateMachineTransition::get_priority() const { + return priority; +} + +void AnimationNodeStateMachineTransition::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_switch_mode", "mode"), &AnimationNodeStateMachineTransition::set_switch_mode); + ClassDB::bind_method(D_METHOD("get_switch_mode"), &AnimationNodeStateMachineTransition::get_switch_mode); + + ClassDB::bind_method(D_METHOD("set_auto_advance", "auto_advance"), &AnimationNodeStateMachineTransition::set_auto_advance); + ClassDB::bind_method(D_METHOD("has_auto_advance"), &AnimationNodeStateMachineTransition::has_auto_advance); + + ClassDB::bind_method(D_METHOD("set_xfade_time", "secs"), &AnimationNodeStateMachineTransition::set_xfade_time); + ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeStateMachineTransition::get_xfade_time); + + ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &AnimationNodeStateMachineTransition::set_disabled); + ClassDB::bind_method(D_METHOD("is_disabled"), &AnimationNodeStateMachineTransition::is_disabled); + + ClassDB::bind_method(D_METHOD("set_priority", "priority"), &AnimationNodeStateMachineTransition::set_priority); + ClassDB::bind_method(D_METHOD("get_priority"), &AnimationNodeStateMachineTransition::get_priority); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,AtEnd"), "set_switch_mode", "get_switch_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_advance"), "set_auto_advance", "has_auto_advance"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01"), "set_xfade_time", "get_xfade_time"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); + + BIND_CONSTANT(SWITCH_MODE_IMMEDIATE); + BIND_CONSTANT(SWITCH_MODE_SYNC); + BIND_CONSTANT(SWITCH_MODE_AT_END); +} + +AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() { + + switch_mode = SWITCH_MODE_IMMEDIATE; + auto_advance = false; + xfade = 0; + disabled = false; + priority = 1; +} + +/////////////////////////////////////////////////////// +void AnimationNodeStateMachine::add_node(const StringName &p_name, Ref<AnimationNode> p_node) { + + ERR_FAIL_COND(states.has(p_name)); + ERR_FAIL_COND(p_node.is_null()); + ERR_FAIL_COND(p_node->get_parent().is_valid()); + ERR_FAIL_COND(p_node->get_tree() != NULL); + ERR_FAIL_COND(String(p_name).find("/") != -1); + states[p_name] = p_node; + + p_node->set_parent(this); + p_node->set_tree(get_tree()); + + emit_changed(); +} + +Ref<AnimationNode> AnimationNodeStateMachine::get_node(const StringName &p_name) const { + + ERR_FAIL_COND_V(!states.has(p_name), Ref<AnimationNode>()); + + return states[p_name]; +} + +StringName AnimationNodeStateMachine::get_node_name(const Ref<AnimationNode> &p_node) const { + for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) { + if (E->get() == p_node) { + return E->key(); + } + } + + ERR_FAIL_V(StringName()); +} + +bool AnimationNodeStateMachine::has_node(const StringName &p_name) const { + return states.has(p_name); +} +void AnimationNodeStateMachine::remove_node(const StringName &p_name) { + + ERR_FAIL_COND(!states.has(p_name)); + + { + //erase node connections + Ref<AnimationNode> node = states[p_name]; + for (int i = 0; i < node->get_input_count(); i++) { + node->set_input_connection(i, StringName()); + } + node->set_parent(NULL); + node->set_tree(NULL); + } + + states.erase(p_name); + path.erase(p_name); + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == p_name || transitions[i].to == p_name) { + transitions.remove(i); + i--; + } + } + + if (start_node == p_name) { + start_node = StringName(); + } + + if (end_node == p_name) { + end_node = StringName(); + } + + if (playing && current == p_name) { + stop(); + } + emit_changed(); +} + +void AnimationNodeStateMachine::rename_node(const StringName &p_name, const StringName &p_new_name) { + + ERR_FAIL_COND(!states.has(p_name)); + ERR_FAIL_COND(states.has(p_new_name)); + + states[p_new_name] = states[p_name]; + states.erase(p_name); + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == p_name) { + transitions[i].from = p_new_name; + } + + if (transitions[i].to == p_name) { + transitions[i].to = p_new_name; + } + } + + if (start_node == p_name) { + start_node = p_new_name; + } + + if (end_node == p_name) { + end_node = p_new_name; + } + + if (playing && current == p_name) { + current = p_new_name; + } + + path.clear(); //clear path +} + +void AnimationNodeStateMachine::get_node_list(List<StringName> *r_nodes) const { + + List<StringName> nodes; + for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) { + nodes.push_back(E->key()); + } + nodes.sort_custom<StringName::AlphCompare>(); + + for (List<StringName>::Element *E = nodes.front(); E; E = E->next()) { + r_nodes->push_back(E->get()); + } +} + +bool AnimationNodeStateMachine::has_transition(const StringName &p_from, const StringName &p_to) const { + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == p_from && transitions[i].to == p_to) + return true; + } + return false; +} + +int AnimationNodeStateMachine::find_transition(const StringName &p_from, const StringName &p_to) const { + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == p_from && transitions[i].to == p_to) + return i; + } + return -1; +} + +void AnimationNodeStateMachine::add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition) { + + ERR_FAIL_COND(p_from == p_to); + ERR_FAIL_COND(!states.has(p_from)); + ERR_FAIL_COND(!states.has(p_to)); + ERR_FAIL_COND(p_transition.is_null()); + + for (int i = 0; i < transitions.size(); i++) { + ERR_FAIL_COND(transitions[i].from == p_from && transitions[i].to == p_to); + } + + Transition tr; + tr.from = p_from; + tr.to = p_to; + tr.transition = p_transition; + + transitions.push_back(tr); +} + +Ref<AnimationNodeStateMachineTransition> AnimationNodeStateMachine::get_transition(int p_transition) const { + ERR_FAIL_INDEX_V(p_transition, transitions.size(), Ref<AnimationNodeStateMachineTransition>()); + return transitions[p_transition].transition; +} +StringName AnimationNodeStateMachine::get_transition_from(int p_transition) const { + + ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName()); + return transitions[p_transition].from; +} +StringName AnimationNodeStateMachine::get_transition_to(int p_transition) const { + + ERR_FAIL_INDEX_V(p_transition, transitions.size(), StringName()); + return transitions[p_transition].to; +} + +int AnimationNodeStateMachine::get_transition_count() const { + + return transitions.size(); +} +void AnimationNodeStateMachine::remove_transition(const StringName &p_from, const StringName &p_to) { + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == p_from && transitions[i].to == p_to) { + transitions.remove(i); + return; + } + } + + if (playing) { + path.clear(); + } +} + +void AnimationNodeStateMachine::remove_transition_by_index(int p_transition) { + + transitions.remove(p_transition); + if (playing) { + path.clear(); + } +} + +void AnimationNodeStateMachine::set_start_node(const StringName &p_node) { + + ERR_FAIL_COND(p_node != StringName() && !states.has(p_node)); + start_node = p_node; +} + +String AnimationNodeStateMachine::get_start_node() const { + + return start_node; +} + +void AnimationNodeStateMachine::set_end_node(const StringName &p_node) { + + ERR_FAIL_COND(p_node != StringName() && !states.has(p_node)); + end_node = p_node; +} + +String AnimationNodeStateMachine::get_end_node() const { + + return end_node; +} + +void AnimationNodeStateMachine::set_graph_offset(const Vector2 &p_offset) { + graph_offset = p_offset; +} + +Vector2 AnimationNodeStateMachine::get_graph_offset() const { + return graph_offset; +} + +float AnimationNodeStateMachine::process(float p_time, bool p_seek) { + + //if not playing and it can restart, then restart + if (!playing) { + if (start_node) { + start(start_node); + } else { + return 0; + } + } + + bool do_start = (p_seek && p_time == 0) || play_start || current == StringName(); + + if (do_start) { + + if (start_node != StringName() && p_seek && p_time == 0) { + current = start_node; + } + + len_current = blend_node(states[current], 0, true, 1.0, FILTER_IGNORE, false); + pos_current = 0; + loops_current = 0; + play_start = false; + } + + float fade_blend = 1.0; + + if (fading_from != StringName()) { + + if (!p_seek) { + fading_pos += p_time; + } + fade_blend = MIN(1.0, fading_pos / fading_time); + if (fade_blend >= 1.0) { + fading_from = StringName(); + } + } + + float rem = blend_node(states[current], p_time, p_seek, fade_blend, FILTER_IGNORE, false); + + if (fading_from != StringName()) { + + blend_node(states[fading_from], p_time, p_seek, 1.0 - fade_blend, FILTER_IGNORE, false); + } + + //guess playback position + if (rem > len_current) { // weird but ok + len_current = rem; + } + + { //advance and loop check + + float next_pos = len_current - rem; + + if (next_pos < pos_current) { + loops_current++; + } + pos_current = next_pos; //looped + } + + //find next + StringName next; + float next_xfade = 0; + AnimationNodeStateMachineTransition::SwitchMode switch_mode = AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE; + + if (path.size()) { + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == current && transitions[i].to == path[0]) { + next_xfade = transitions[i].transition->get_xfade_time(); + switch_mode = transitions[i].transition->get_switch_mode(); + next = path[0]; + } + } + } else { + float priority_best = 1e20; + int auto_advance_to = -1; + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == current && transitions[i].transition->has_auto_advance()) { + + if (transitions[i].transition->get_priority() < priority_best) { + auto_advance_to = i; + } + } + } + + if (auto_advance_to != -1) { + next = transitions[auto_advance_to].to; + next_xfade = transitions[auto_advance_to].transition->get_xfade_time(); + switch_mode = transitions[auto_advance_to].transition->get_switch_mode(); + } + } + + //if next, see when to transition + if (next != StringName()) { + + bool goto_next = false; + + if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE) { + goto_next = fading_from == StringName(); + } else { + goto_next = next_xfade >= (len_current - pos_current) || loops_current > 0; + if (loops_current > 0) { + next_xfade = 0; + } + } + + if (goto_next) { //loops should be used because fade time may be too small or zero and animation may have looped + + if (next_xfade) { + //time to fade, baby + fading_from = current; + fading_time = next_xfade; + fading_pos = 0; + } else { + fading_from = StringName(); + fading_pos = 0; + } + + if (path.size()) { //if it came from path, remove path + path.remove(0); + } + current = next; + if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) { + len_current = blend_node(states[current], 0, true, 0, FILTER_IGNORE, false); + pos_current = MIN(pos_current, len_current); + blend_node(states[current], pos_current, true, 0, FILTER_IGNORE, false); + + } else { + len_current = blend_node(states[current], 0, true, 0, FILTER_IGNORE, false); + pos_current = 0; + } + + rem = len_current; //so it does not show 0 on transition + loops_current = 0; + } + } + + //compute time left for transitions by using the end node + + if (end_node != StringName() && end_node != current) { + + rem = blend_node(states[end_node], 0, true, 0, FILTER_IGNORE, false); + } + + return rem; +} + +bool AnimationNodeStateMachine::travel(const StringName &p_state) { + ERR_FAIL_COND_V(!playing, false); + ERR_FAIL_COND_V(!states.has(p_state), false); + ERR_FAIL_COND_V(!states.has(current), false); + + path.clear(); //a new one will be needed + + if (current == p_state) + return true; //nothing to do + + loops_current = 0; // reset loops, so fade does not happen immediately + + Vector2 current_pos = states[current]->get_position(); + Vector2 target_pos = states[p_state]->get_position(); + + Map<StringName, AStarCost> cost_map; + + List<int> open_list; + + //build open list + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from == current) { + open_list.push_back(i); + float cost = states[transitions[i].to]->get_position().distance_to(current_pos); + cost *= transitions[i].transition->get_priority(); + AStarCost ap; + ap.prev = current; + ap.distance = cost; + cost_map[transitions[i].to] = ap; + + if (transitions[i].to == p_state) { //prematurely found it! :D + path.push_back(p_state); + return true; + } + } + } + + //begin astar + bool found_route = false; + while (!found_route) { + + if (open_list.size() == 0) { + return false; //no path found + } + + //find the last cost transition + List<int>::Element *least_cost_transition = NULL; + float least_cost = 1e20; + + for (List<int>::Element *E = open_list.front(); E; E = E->next()) { + + float cost = cost_map[transitions[E->get()].to].distance; + cost += states[transitions[E->get()].to]->get_position().distance_to(target_pos); + + if (cost < least_cost) { + least_cost_transition = E; + } + } + + StringName transition_prev = transitions[least_cost_transition->get()].from; + StringName transition = transitions[least_cost_transition->get()].to; + + for (int i = 0; i < transitions.size(); i++) { + if (transitions[i].from != transition || transitions[i].to == transition_prev) { + continue; //not interested on those + } + + float distance = states[transitions[i].from]->get_position().distance_to(states[transitions[i].to]->get_position()); + distance *= transitions[i].transition->get_priority(); + distance += cost_map[transitions[i].from].distance; + + if (cost_map.has(transitions[i].to)) { + //oh this was visited already, can we win the cost? + if (distance < cost_map[transitions[i].to].distance) { + cost_map[transitions[i].to].distance = distance; + cost_map[transitions[i].to].prev = transitions[i].from; + } + } else { + //add to open list + AStarCost ac; + ac.prev = transitions[i].from; + ac.distance = distance; + cost_map[transitions[i].to] = ac; + + open_list.push_back(i); + + if (transitions[i].to == p_state) { + found_route = true; + break; + } + } + } + + if (found_route) { + break; + } + + open_list.erase(least_cost_transition); + } + + //make path + StringName at = p_state; + while (at != current) { + path.push_back(at); + at = cost_map[at].prev; + } + + path.invert(); + + return true; +} + +void AnimationNodeStateMachine::start(const StringName &p_state) { + + ERR_FAIL_COND(!states.has(p_state)); + path.clear(); + current = p_state; + playing = true; + play_start = true; +} +void AnimationNodeStateMachine::stop() { + playing = false; + play_start = false; + current = StringName(); +} +bool AnimationNodeStateMachine::is_playing() const { + + return playing; +} +StringName AnimationNodeStateMachine::get_current_node() const { + if (!playing) { + return StringName(); + } + + return current; +} + +StringName AnimationNodeStateMachine::get_blend_from_node() const { + if (!playing) { + return StringName(); + } + + return fading_from; +} + +float AnimationNodeStateMachine::get_current_play_pos() const { + return pos_current; +} +float AnimationNodeStateMachine::get_current_length() const { + return len_current; +} + +Vector<StringName> AnimationNodeStateMachine::get_travel_path() const { + return path; +} +String AnimationNodeStateMachine::get_caption() const { + return "StateMachine"; +} + +void AnimationNodeStateMachine::_notification(int p_what) { +} + +void AnimationNodeStateMachine::set_tree(AnimationTree *p_player) { + + AnimationNode::set_tree(p_player); + + for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) { + Ref<AnimationRootNode> node = E->get(); + node->set_tree(p_player); + } +} + +bool AnimationNodeStateMachine::_set(const StringName &p_name, const Variant &p_value) { + + String name = p_name; + if (name.begins_with("states/")) { + String node_name = name.get_slicec('/', 1); + String what = name.get_slicec('/', 2); + + if (what == "node") { + Ref<AnimationNode> anode = p_value; + if (anode.is_valid()) { + add_node(node_name, p_value); + } + return true; + } + + if (what == "position") { + + if (states.has(node_name)) { + states[node_name]->set_position(p_value); + } + return true; + } + } else if (name == "transitions") { + + Array trans = p_value; + ERR_FAIL_COND_V(trans.size() % 3 != 0, false); + + for (int i = 0; i < trans.size(); i += 3) { + add_transition(trans[i], trans[i + 1], trans[i + 2]); + } + return true; + } else if (name == "start_node") { + set_start_node(p_value); + return true; + } else if (name == "end_node") { + set_end_node(p_value); + return true; + } else if (name == "graph_offset") { + set_graph_offset(p_value); + return true; + } + + return false; +} + +bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) const { + + String name = p_name; + if (name.begins_with("states/")) { + String node_name = name.get_slicec('/', 1); + String what = name.get_slicec('/', 2); + + if (what == "node") { + if (states.has(node_name)) { + r_ret = states[node_name]; + return true; + } + } + + if (what == "position") { + + if (states.has(node_name)) { + r_ret = states[node_name]->get_position(); + return true; + } + } + } else if (name == "transitions") { + Array trans; + trans.resize(transitions.size() * 3); + + for (int i = 0; i < transitions.size(); i++) { + trans[i * 3 + 0] = transitions[i].from; + trans[i * 3 + 1] = transitions[i].to; + trans[i * 3 + 2] = transitions[i].transition; + } + + r_ret = trans; + return true; + } else if (name == "start_node") { + r_ret = get_start_node(); + return true; + } else if (name == "end_node") { + r_ret = get_end_node(); + return true; + } else if (name == "graph_offset") { + r_ret = get_graph_offset(); + return true; + } + + return false; +} +void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) const { + + List<StringName> names; + for (Map<StringName, Ref<AnimationRootNode> >::Element *E = states.front(); E; E = E->next()) { + names.push_back(E->key()); + } + names.sort_custom<StringName::AlphCompare>(); + + for (List<StringName>::Element *E = names.front(); E; E = E->next()) { + String name = E->get(); + p_list->push_back(PropertyInfo(Variant::OBJECT, "states/" + name + "/node", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNode", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "states/" + name + "/position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + } + + p_list->push_back(PropertyInfo(Variant::ARRAY, "transitions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::STRING, "start_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::STRING, "end_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); + p_list->push_back(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); +} + +void AnimationNodeStateMachine::_bind_methods() { + + ClassDB::bind_method(D_METHOD("add_node", "name", "node"), &AnimationNodeStateMachine::add_node); + ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeStateMachine::get_node); + ClassDB::bind_method(D_METHOD("remove_node", "name"), &AnimationNodeStateMachine::remove_node); + ClassDB::bind_method(D_METHOD("rename_node", "name", "new_name"), &AnimationNodeStateMachine::rename_node); + ClassDB::bind_method(D_METHOD("has_node", "name"), &AnimationNodeStateMachine::has_node); + ClassDB::bind_method(D_METHOD("get_node_name", "node"), &AnimationNodeStateMachine::get_node_name); + + ClassDB::bind_method(D_METHOD("has_transition", "from", "to"), &AnimationNodeStateMachine::add_transition); + ClassDB::bind_method(D_METHOD("add_transition", "from", "to", "transition"), &AnimationNodeStateMachine::add_transition); + ClassDB::bind_method(D_METHOD("get_transition", "idx"), &AnimationNodeStateMachine::get_transition); + ClassDB::bind_method(D_METHOD("get_transition_from", "idx"), &AnimationNodeStateMachine::get_transition_from); + ClassDB::bind_method(D_METHOD("get_transition_to", "idx"), &AnimationNodeStateMachine::get_transition_to); + ClassDB::bind_method(D_METHOD("get_transition_count"), &AnimationNodeStateMachine::get_transition_count); + ClassDB::bind_method(D_METHOD("remove_transition_by_index", "idx"), &AnimationNodeStateMachine::remove_transition_by_index); + ClassDB::bind_method(D_METHOD("remove_transition", "from", "to"), &AnimationNodeStateMachine::remove_transition); + + ClassDB::bind_method(D_METHOD("set_start_node", "name"), &AnimationNodeStateMachine::set_start_node); + ClassDB::bind_method(D_METHOD("get_start_node"), &AnimationNodeStateMachine::get_start_node); + + ClassDB::bind_method(D_METHOD("set_end_node", "name"), &AnimationNodeStateMachine::set_end_node); + ClassDB::bind_method(D_METHOD("get_end_node"), &AnimationNodeStateMachine::get_end_node); + + ClassDB::bind_method(D_METHOD("set_graph_offset", "name"), &AnimationNodeStateMachine::set_graph_offset); + ClassDB::bind_method(D_METHOD("get_graph_offset"), &AnimationNodeStateMachine::get_graph_offset); + + ClassDB::bind_method(D_METHOD("travel", "to_node"), &AnimationNodeStateMachine::travel); + ClassDB::bind_method(D_METHOD("start", "node"), &AnimationNodeStateMachine::start); + ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeStateMachine::stop); + ClassDB::bind_method(D_METHOD("is_playing"), &AnimationNodeStateMachine::is_playing); + ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachine::get_current_node); + ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachine::get_travel_path); +} + +AnimationNodeStateMachine::AnimationNodeStateMachine() { + + play_start = false; + + playing = false; + len_current = 0; + + fading_time = 0; +} diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h new file mode 100644 index 0000000000..e7357e09ea --- /dev/null +++ b/scene/animation/animation_node_state_machine.h @@ -0,0 +1,142 @@ +#ifndef ANIMATION_NODE_STATE_MACHINE_H +#define ANIMATION_NODE_STATE_MACHINE_H + +#include "scene/animation/animation_tree.h" + +class AnimationNodeStateMachineTransition : public Resource { + GDCLASS(AnimationNodeStateMachineTransition, Resource) +public: + enum SwitchMode { + SWITCH_MODE_IMMEDIATE, + SWITCH_MODE_SYNC, + SWITCH_MODE_AT_END, + }; + +private: + SwitchMode switch_mode; + bool auto_advance; + float xfade; + bool disabled; + int priority; + +protected: + static void _bind_methods(); + +public: + void set_switch_mode(SwitchMode p_mode); + SwitchMode get_switch_mode() const; + + void set_auto_advance(bool p_enable); + bool has_auto_advance() const; + + void set_xfade_time(float p_xfade); + float get_xfade_time() const; + + void set_disabled(bool p_disabled); + bool is_disabled() const; + + void set_priority(int p_priority); + int get_priority() const; + + AnimationNodeStateMachineTransition(); +}; + +VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode) + +class AnimationNodeStateMachine : public AnimationRootNode { + + GDCLASS(AnimationNodeStateMachine, AnimationRootNode); + +private: + Map<StringName, Ref<AnimationRootNode> > states; + + struct Transition { + + StringName from; + StringName to; + Ref<AnimationNodeStateMachineTransition> transition; + }; + + struct AStarCost { + float distance; + StringName prev; + }; + + Vector<Transition> transitions; + + float len_total; + + float len_current; + float pos_current; + int loops_current; + + bool play_start; + StringName start_node; + StringName end_node; + + Vector2 graph_offset; + + StringName current; + + StringName fading_from; + float fading_time; + float fading_pos; + + Vector<StringName> path; + bool playing; + +protected: + void _notification(int p_what); + static void _bind_methods(); + + 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; + +public: + void add_node(const StringName &p_name, Ref<AnimationNode> p_node); + Ref<AnimationNode> get_node(const StringName &p_name) const; + void remove_node(const StringName &p_name); + void rename_node(const StringName &p_name, const StringName &p_new_name); + bool has_node(const StringName &p_name) const; + StringName get_node_name(const Ref<AnimationNode> &p_node) const; + void get_node_list(List<StringName> *r_nodes) const; + + bool has_transition(const StringName &p_from, const StringName &p_to) const; + int find_transition(const StringName &p_from, const StringName &p_to) const; + void add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition); + Ref<AnimationNodeStateMachineTransition> get_transition(int p_transition) const; + StringName get_transition_from(int p_transition) const; + StringName get_transition_to(int p_transition) const; + int get_transition_count() const; + void remove_transition_by_index(int p_transition); + void remove_transition(const StringName &p_from, const StringName &p_to); + + void set_start_node(const StringName &p_node); + String get_start_node() const; + + void set_end_node(const StringName &p_node); + String get_end_node() const; + + void set_graph_offset(const Vector2 &p_offset); + Vector2 get_graph_offset() const; + + virtual float process(float p_time, bool p_seek); + virtual String get_caption() const; + + bool travel(const StringName &p_state); + void start(const StringName &p_state); + void stop(); + bool is_playing() const; + StringName get_current_node() const; + StringName get_blend_from_node() const; + Vector<StringName> get_travel_path() const; + float get_current_play_pos() const; + float get_current_length() const; + + virtual void set_tree(AnimationTree *p_player); + + AnimationNodeStateMachine(); +}; + +#endif // ANIMATION_NODE_STATE_MACHINE_H diff --git a/scene/animation/animation_graph_player.cpp b/scene/animation/animation_tree.cpp index b8efecebe9..7cc67b4cc3 100644 --- a/scene/animation/animation_graph_player.cpp +++ b/scene/animation/animation_tree.cpp @@ -1,4 +1,4 @@ -#include "animation_graph_player.h" +#include "animation_tree.h" #include "animation_blend_tree.h" #include "core/method_bind_ext.gen.inc" #include "engine.h" @@ -56,11 +56,11 @@ void AnimationNode::make_invalid(const String &p_reason) { float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p_blend, FilterAction p_filter, bool p_optimize) { ERR_FAIL_INDEX_V(p_input, inputs.size(), 0); ERR_FAIL_COND_V(!state, 0); - ERR_FAIL_COND_V(!get_graph_player(), 0); //should not happen, but used to catch bugs + ERR_FAIL_COND_V(!get_tree(), 0); //should not happen, but used to catch bugs Ref<AnimationNodeBlendTree> tree = get_parent(); - if (!tree.is_valid() && get_graph_player()->get_graph_root().ptr() != this) { + if (!tree.is_valid() && get_tree()->get_graph_root().ptr() != this) { make_invalid(RTR("Can't blend input because node is not in a tree")); return 0; } @@ -204,10 +204,10 @@ String AnimationNode::get_input_name(int p_input) { float AnimationNode::get_input_activity(int p_input) const { ERR_FAIL_INDEX_V(p_input, inputs.size(), 0); - if (!get_graph_player()) + if (!get_tree()) return 0; - if (get_graph_player()->get_last_process_pass() != inputs[p_input].last_pass) { + if (get_tree()->get_last_process_pass() != inputs[p_input].last_pass) { return 0; } return inputs[p_input].activity; @@ -265,7 +265,7 @@ Ref<AnimationNode> AnimationNode::get_parent() const { return Ref<AnimationNode>(); } -AnimationGraphPlayer *AnimationNode::get_graph_player() const { +AnimationTree *AnimationNode::get_tree() const { return player; } @@ -316,7 +316,7 @@ Vector2 AnimationNode::get_position() const { return position; } -void AnimationNode::set_graph_player(AnimationGraphPlayer *p_player) { +void AnimationNode::set_tree(AnimationTree *p_player) { if (player != NULL && p_player == NULL) { emit_signal("removed_from_graph"); @@ -398,10 +398,10 @@ AnimationNode::AnimationNode() { //////////////////// -void AnimationGraphPlayer::set_graph_root(const Ref<AnimationNode> &p_root) { +void AnimationTree::set_graph_root(const Ref<AnimationNode> &p_root) { if (root.is_valid()) { - root->set_graph_player(NULL); + root->set_tree(NULL); } if (p_root.is_valid()) { ERR_EXPLAIN("root node already set to another player"); @@ -410,17 +410,17 @@ void AnimationGraphPlayer::set_graph_root(const Ref<AnimationNode> &p_root) { root = p_root; if (root.is_valid()) { - root->set_graph_player(this); + root->set_tree(this); } update_configuration_warning(); } -Ref<AnimationNode> AnimationGraphPlayer::get_graph_root() const { +Ref<AnimationNode> AnimationTree::get_graph_root() const { return root; } -void AnimationGraphPlayer::set_active(bool p_active) { +void AnimationTree::set_active(bool p_active) { if (active == p_active) return; @@ -447,12 +447,12 @@ void AnimationGraphPlayer::set_active(bool p_active) { } } -bool AnimationGraphPlayer::is_active() const { +bool AnimationTree::is_active() const { return active; } -void AnimationGraphPlayer::set_process_mode(AnimationProcessMode p_mode) { +void AnimationTree::set_process_mode(AnimationProcessMode p_mode) { if (process_mode == p_mode) return; @@ -469,20 +469,20 @@ void AnimationGraphPlayer::set_process_mode(AnimationProcessMode p_mode) { } } -AnimationGraphPlayer::AnimationProcessMode AnimationGraphPlayer::get_process_mode() const { +AnimationTree::AnimationProcessMode AnimationTree::get_process_mode() const { return process_mode; } -void AnimationGraphPlayer::_node_removed(Node *p_node) { +void AnimationTree::_node_removed(Node *p_node) { cache_valid = false; } -bool AnimationGraphPlayer::_update_caches(AnimationPlayer *player) { +bool AnimationTree::_update_caches(AnimationPlayer *player) { setup_pass++; if (!player->has_node(player->get_root())) { - ERR_PRINT("AnimationGraphPlayer: AnimationPlayer root is invalid."); + ERR_PRINT("AnimationTree: AnimationPlayer root is invalid."); set_active(false); return false; } @@ -517,7 +517,7 @@ bool AnimationGraphPlayer::_update_caches(AnimationPlayer *player) { Node *child = parent->get_node_and_resource(path, resource, leftover_path); if (!child) { - ERR_PRINTS("AnimationGraphPlayer: '" + String(E->get()) + "', couldn't resolve track: '" + String(path) + "'"); + ERR_PRINTS("AnimationTree: '" + String(E->get()) + "', couldn't resolve track: '" + String(path) + "'"); continue; } @@ -547,7 +547,7 @@ bool AnimationGraphPlayer::_update_caches(AnimationPlayer *player) { Spatial *spatial = Object::cast_to<Spatial>(child); if (!spatial) { - ERR_PRINTS("AnimationGraphPlayer: '" + String(E->get()) + "', transform track does not point to spatial: '" + String(path) + "'"); + ERR_PRINTS("AnimationTree: '" + String(E->get()) + "', transform track does not point to spatial: '" + String(path) + "'"); continue; } @@ -666,7 +666,7 @@ bool AnimationGraphPlayer::_update_caches(AnimationPlayer *player) { return true; } -void AnimationGraphPlayer::_clear_caches() { +void AnimationTree::_clear_caches() { const NodePath *K = NULL; while ((K = track_cache.next(K))) { @@ -678,19 +678,19 @@ void AnimationGraphPlayer::_clear_caches() { cache_valid = false; } -void AnimationGraphPlayer::_process_graph(float p_delta) { +void AnimationTree::_process_graph(float p_delta) { //check all tracks, see if they need modification if (!root.is_valid()) { - ERR_PRINT("AnimationGraphPlayer: root AnimationNode is not set, disabling playback."); + ERR_PRINT("AnimationTree: root AnimationNode is not set, disabling playback."); set_active(false); cache_valid = false; return; } if (!has_node(animation_player)) { - ERR_PRINT("AnimationGraphPlayer: no valid AnimationPlayer path set, disabling playback"); + ERR_PRINT("AnimationTree: no valid AnimationPlayer path set, disabling playback"); set_active(false); cache_valid = false; return; @@ -699,7 +699,7 @@ void AnimationGraphPlayer::_process_graph(float p_delta) { AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player)); if (!player) { - ERR_PRINT("AnimationGraphPlayer: path points to a node not an AnimationPlayer, disabling playback"); + ERR_PRINT("AnimationTree: path points to a node not an AnimationPlayer, disabling playback"); set_active(false); cache_valid = false; return; @@ -1093,7 +1093,7 @@ void AnimationGraphPlayer::_process_graph(float p_delta) { } } -void AnimationGraphPlayer::_notification(int p_what) { +void AnimationTree::_notification(int p_what) { if (active && p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_mode == ANIMATION_PROCESS_PHYSICS) { _process_graph(get_physics_process_delta_time()); @@ -1108,29 +1108,29 @@ void AnimationGraphPlayer::_notification(int p_what) { } } -void AnimationGraphPlayer::set_animation_player(const NodePath &p_player) { +void AnimationTree::set_animation_player(const NodePath &p_player) { animation_player = p_player; update_configuration_warning(); } -NodePath AnimationGraphPlayer::get_animation_player() const { +NodePath AnimationTree::get_animation_player() const { return animation_player; } -bool AnimationGraphPlayer::is_state_invalid() const { +bool AnimationTree::is_state_invalid() const { return !state.valid; } -String AnimationGraphPlayer::get_invalid_state_reason() const { +String AnimationTree::get_invalid_state_reason() const { return state.invalid_reasons; } -uint64_t AnimationGraphPlayer::get_last_process_pass() const { +uint64_t AnimationTree::get_last_process_pass() const { return process_pass; } -String AnimationGraphPlayer::get_configuration_warning() const { +String AnimationTree::get_configuration_warning() const { String warning = Node::get_configuration_warning(); @@ -1174,20 +1174,20 @@ String AnimationGraphPlayer::get_configuration_warning() const { return warning; } -void AnimationGraphPlayer::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationGraphPlayer::set_active); - ClassDB::bind_method(D_METHOD("is_active"), &AnimationGraphPlayer::is_active); +void AnimationTree::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_active", "active"), &AnimationTree::set_active); + ClassDB::bind_method(D_METHOD("is_active"), &AnimationTree::is_active); - ClassDB::bind_method(D_METHOD("set_graph_root", "root"), &AnimationGraphPlayer::set_graph_root); - ClassDB::bind_method(D_METHOD("get_graph_root"), &AnimationGraphPlayer::get_graph_root); + ClassDB::bind_method(D_METHOD("set_graph_root", "root"), &AnimationTree::set_graph_root); + ClassDB::bind_method(D_METHOD("get_graph_root"), &AnimationTree::get_graph_root); - ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &AnimationGraphPlayer::set_process_mode); - ClassDB::bind_method(D_METHOD("get_process_mode"), &AnimationGraphPlayer::get_process_mode); + ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &AnimationTree::set_process_mode); + ClassDB::bind_method(D_METHOD("get_process_mode"), &AnimationTree::get_process_mode); - ClassDB::bind_method(D_METHOD("set_animation_player", "root"), &AnimationGraphPlayer::set_animation_player); - ClassDB::bind_method(D_METHOD("get_animation_player"), &AnimationGraphPlayer::get_animation_player); + ClassDB::bind_method(D_METHOD("set_animation_player", "root"), &AnimationTree::set_animation_player); + ClassDB::bind_method(D_METHOD("get_animation_player"), &AnimationTree::get_animation_player); - ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationGraphPlayer::_node_removed); + ClassDB::bind_method(D_METHOD("_node_removed"), &AnimationTree::_node_removed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "graph_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_graph_root", "get_graph_root"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player"), "set_animation_player", "get_animation_player"); @@ -1195,7 +1195,7 @@ void AnimationGraphPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode"); } -AnimationGraphPlayer::AnimationGraphPlayer() { +AnimationTree::AnimationTree() { process_mode = ANIMATION_PROCESS_IDLE; active = false; @@ -1204,7 +1204,7 @@ AnimationGraphPlayer::AnimationGraphPlayer() { started = true; } -AnimationGraphPlayer::~AnimationGraphPlayer() { +AnimationTree::~AnimationTree() { if (root.is_valid()) { root->player = NULL; } diff --git a/scene/animation/animation_graph_player.h b/scene/animation/animation_tree.h index 8952be75c9..adc25d5607 100644 --- a/scene/animation/animation_graph_player.h +++ b/scene/animation/animation_tree.h @@ -8,7 +8,7 @@ class AnimationNodeBlendTree; class AnimationPlayer; -class AnimationGraphPlayer; +class AnimationTree; class AnimationNode : public Resource { GDCLASS(AnimationNode, Resource) @@ -32,7 +32,7 @@ public: float process_input(int p_input, float p_time, bool p_seek, float p_blend); - friend class AnimationGraphPlayer; + friend class AnimationTree; struct AnimationState { @@ -62,7 +62,7 @@ public: Vector2 position; AnimationNode *parent; - AnimationGraphPlayer *player; + AnimationTree *player; float _blend_node(Ref<AnimationNode> p_node, float p_time, bool p_seek, float p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_optimize = true, float *r_max = NULL); @@ -85,8 +85,8 @@ protected: public: void set_parent(AnimationNode *p_parent); Ref<AnimationNode> get_parent() const; - virtual void set_graph_player(AnimationGraphPlayer *p_player); - AnimationGraphPlayer *get_graph_player() const; + virtual void set_tree(AnimationTree *p_player); + AnimationTree *get_tree() const; AnimationPlayer *get_player() const; virtual float process(float p_time, bool p_seek); @@ -125,8 +125,8 @@ public: AnimationRootNode() {} }; -class AnimationGraphPlayer : public Node { - GDCLASS(AnimationGraphPlayer, Node) +class AnimationTree : public Node { + GDCLASS(AnimationTree, Node) public: enum AnimationProcessMode { ANIMATION_PROCESS_PHYSICS, @@ -258,10 +258,10 @@ public: String get_invalid_state_reason() const; uint64_t get_last_process_pass() const; - AnimationGraphPlayer(); - ~AnimationGraphPlayer(); + AnimationTree(); + ~AnimationTree(); }; -VARIANT_ENUM_CAST(AnimationGraphPlayer::AnimationProcessMode) +VARIANT_ENUM_CAST(AnimationTree::AnimationProcessMode) #endif // ANIMATION_GRAPH_PLAYER_H |