diff options
-rw-r--r-- | doc/classes/AnimationNode.xml | 21 | ||||
-rw-r--r-- | doc/classes/AnimationNodeTransition.xml | 26 | ||||
-rw-r--r-- | scene/animation/animation_blend_tree.cpp | 150 | ||||
-rw-r--r-- | scene/animation/animation_blend_tree.h | 27 | ||||
-rw-r--r-- | scene/animation/animation_tree.cpp | 58 | ||||
-rw-r--r-- | scene/animation/animation_tree.h | 10 |
6 files changed, 152 insertions, 140 deletions
diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index 6e3345b675..bc65e6013b 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -68,10 +68,10 @@ </description> </method> <method name="add_input"> - <return type="void" /> + <return type="bool" /> <param index="0" name="name" type="String" /> <description> - Adds an input to the node. This is only useful for nodes created for use in an [AnimationNodeBlendTree]. + Adds an input to the node. This is only useful for nodes created for use in an [AnimationNodeBlendTree]. If the addition fails, returns [code]false[/code]. </description> </method> <method name="blend_animation"> @@ -115,13 +115,20 @@ Blend another animation node (in case this node contains children animation nodes). This function is only useful if you inherit from [AnimationRootNode] instead, else editors will not display your node for addition. </description> </method> + <method name="find_input" qualifiers="const"> + <return type="int" /> + <param index="0" name="name" type="String" /> + <description> + Returns the input index which corresponds to [param name]. If not found, returns [code]-1[/code]. + </description> + </method> <method name="get_input_count" qualifiers="const"> <return type="int" /> <description> Amount of inputs in this node, only useful for nodes that go into [AnimationNodeBlendTree]. </description> </method> - <method name="get_input_name"> + <method name="get_input_name" qualifiers="const"> <return type="String" /> <param index="0" name="input" type="int" /> <description> @@ -157,6 +164,14 @@ Adds or removes a path for the filter. </description> </method> + <method name="set_input_name"> + <return type="bool" /> + <param index="0" name="input" type="int" /> + <param index="1" name="name" type="String" /> + <description> + Sets the name of the input at the given [param input] index. If the setting fails, returns [code]false[/code]. + </description> + </method> <method name="set_parameter"> <return type="void" /> <param index="0" name="name" type="StringName" /> diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml index 90bae41586..57e79ac161 100644 --- a/doc/classes/AnimationNodeTransition.xml +++ b/doc/classes/AnimationNodeTransition.xml @@ -12,20 +12,6 @@ <link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link> </tutorials> <methods> - <method name="find_input_caption" qualifiers="const"> - <return type="int" /> - <param index="0" name="caption" type="String" /> - <description> - Returns the input index which corresponds to [param caption]. If not found, returns [code]-1[/code]. - </description> - </method> - <method name="get_input_caption" qualifiers="const"> - <return type="String" /> - <param index="0" name="input" type="int" /> - <description> - Returns the name of the input at the given [param input] index. This name is displayed in the editor next to the node input. - </description> - </method> <method name="is_input_set_as_auto_advance" qualifiers="const"> <return type="bool" /> <param index="0" name="input" type="int" /> @@ -41,18 +27,10 @@ Enables or disables auto-advance for the given [param input] index. If enabled, state changes to the next input after playing the animation once. If enabled for the last input state, it loops to the first. </description> </method> - <method name="set_input_caption"> - <return type="void" /> - <param index="0" name="input" type="int" /> - <param index="1" name="caption" type="String" /> - <description> - Sets the name of the input at the given [param input] index. This name is displayed in the editor next to the node input. - </description> - </method> </methods> <members> - <member name="enabled_inputs" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs" default="0"> - The number of enabled input ports for this node. The maximum is [code]31[/code]. + <member name="input_count" type="int" setter="set_input_count" getter="get_input_count" default="0"> + The number of enabled input ports for this node. </member> <member name="reset" type="bool" setter="set_reset" getter="is_reset" default="true"> If [code]true[/code], the destination animation is played back from the beginning when switched. diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index a00b1d8ee1..d2073f4f23 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -644,9 +644,62 @@ AnimationNodeTimeSeek::AnimationNodeTimeSeek() { ///////////////////////////////////////////////// +bool AnimationNodeTransition::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + + if (!path.begins_with("input_")) { + return false; + } + + int which = path.get_slicec('/', 0).get_slicec('_', 1).to_int(); + String what = path.get_slicec('/', 1); + + if (which == get_input_count() && what == "name") { + if (add_input(p_value)) { + return true; + } + return false; + } + + ERR_FAIL_INDEX_V(which, get_input_count(), false); + + if (what == "name") { + set_input_name(which, p_value); + } else if (what == "auto_advance") { + set_input_as_auto_advance(which, p_value); + } else { + return false; + } + + return true; +} + +bool AnimationNodeTransition::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + + if (!path.begins_with("input_")) { + return false; + } + + int which = path.get_slicec('/', 0).get_slicec('_', 1).to_int(); + String what = path.get_slicec('/', 1); + + ERR_FAIL_INDEX_V(which, get_input_count(), false); + + if (what == "name") { + r_ret = get_input_name(which); + } else if (what == "auto_advance") { + r_ret = is_input_set_as_auto_advance(which); + } else { + return false; + } + + return true; +} + void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) const { String anims; - for (int i = 0; i < enabled_inputs; i++) { + for (int i = 0; i < get_input_count(); i++) { if (i > 0) { anims += ","; } @@ -684,56 +737,37 @@ String AnimationNodeTransition::get_caption() const { return "Transition"; } -void AnimationNodeTransition::_update_inputs() { - while (get_input_count() < enabled_inputs) { - add_input(inputs[get_input_count()].name); +void AnimationNodeTransition::set_input_count(int p_inputs) { + for (int i = get_input_count(); i < p_inputs; i++) { + add_input("state_" + itos(i)); } - - while (get_input_count() > enabled_inputs) { + while (get_input_count() > p_inputs) { remove_input(get_input_count() - 1); } + notify_property_list_changed(); } -void AnimationNodeTransition::set_enabled_inputs(int p_inputs) { - ERR_FAIL_INDEX(p_inputs, MAX_INPUTS); - enabled_inputs = p_inputs; - _update_inputs(); +bool AnimationNodeTransition::add_input(const String &p_name) { + if (AnimationNode::add_input(p_name)) { + input_as_auto_advance.push_back(false); + return true; + } + return false; } -int AnimationNodeTransition::get_enabled_inputs() { - return enabled_inputs; +void AnimationNodeTransition::remove_input(int p_index) { + input_as_auto_advance.remove_at(p_index); + AnimationNode::remove_input(p_index); } void AnimationNodeTransition::set_input_as_auto_advance(int p_input, bool p_enable) { - ERR_FAIL_INDEX(p_input, MAX_INPUTS); - inputs[p_input].auto_advance = p_enable; + ERR_FAIL_INDEX(p_input, get_input_count()); + input_as_auto_advance.write[p_input] = p_enable; } bool AnimationNodeTransition::is_input_set_as_auto_advance(int p_input) const { - ERR_FAIL_INDEX_V(p_input, MAX_INPUTS, false); - return inputs[p_input].auto_advance; -} - -void AnimationNodeTransition::set_input_caption(int p_input, const String &p_name) { - ERR_FAIL_INDEX(p_input, MAX_INPUTS); - inputs[p_input].name = p_name; - set_input_name(p_input, p_name); -} - -String AnimationNodeTransition::get_input_caption(int p_input) const { - ERR_FAIL_INDEX_V(p_input, MAX_INPUTS, String()); - return inputs[p_input].name; -} - -int AnimationNodeTransition::find_input_caption(const String &p_name) const { - int idx = -1; - for (int i = 0; i < MAX_INPUTS; i++) { - if (inputs[i].name == p_name) { - idx = i; - break; - } - } - return idx; + ERR_FAIL_INDEX_V(p_input, get_input_count(), false); + return input_as_auto_advance[p_input]; } void AnimationNodeTransition::set_xfade_time(double p_fade) { @@ -772,7 +806,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex bool restart = false; if (!cur_transition_request.is_empty()) { - int new_idx = find_input_caption(cur_transition_request); + int new_idx = find_input(cur_transition_request); if (new_idx >= 0) { if (cur_current_index == new_idx) { // Transition to same state. @@ -807,14 +841,14 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex cur_time = 0; } - if (cur_current_index < 0 || cur_current_index >= enabled_inputs || cur_prev_index >= enabled_inputs) { + if (cur_current_index < 0 || cur_current_index >= get_input_count() || cur_prev_index >= get_input_count()) { return 0; } double rem = 0.0; if (sync) { - for (int i = 0; i < enabled_inputs; i++) { + for (int i = 0; i < get_input_count(); i++) { if (i != cur_current_index && i != cur_prev_index) { blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true); } @@ -831,8 +865,8 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex cur_time += p_time; } - if (inputs[cur_current_index].auto_advance && rem <= xfade_time) { - set_parameter(transition_request, get_input_caption((cur_current_index + 1) % enabled_inputs)); + if (input_as_auto_advance[cur_current_index] && rem <= xfade_time) { + set_parameter(transition_request, get_input_name((cur_current_index + 1) % get_input_count())); } } else { // cross-fading from prev to current @@ -869,29 +903,19 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex return rem; } -void AnimationNodeTransition::_validate_property(PropertyInfo &p_property) const { - if (p_property.name.begins_with("input_")) { - String n = p_property.name.get_slicec('/', 0).get_slicec('_', 1); - if (n != "count") { - int idx = n.to_int(); - if (idx >= enabled_inputs) { - p_property.usage = PROPERTY_USAGE_NONE; - } - } +void AnimationNodeTransition::_get_property_list(List<PropertyInfo> *p_list) const { + for (int i = 0; i < get_input_count(); i++) { + p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/auto_advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL)); } } void AnimationNodeTransition::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_enabled_inputs", "amount"), &AnimationNodeTransition::set_enabled_inputs); - ClassDB::bind_method(D_METHOD("get_enabled_inputs"), &AnimationNodeTransition::get_enabled_inputs); + ClassDB::bind_method(D_METHOD("set_input_count", "input_count"), &AnimationNodeTransition::set_input_count); ClassDB::bind_method(D_METHOD("set_input_as_auto_advance", "input", "enable"), &AnimationNodeTransition::set_input_as_auto_advance); ClassDB::bind_method(D_METHOD("is_input_set_as_auto_advance", "input"), &AnimationNodeTransition::is_input_set_as_auto_advance); - ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption); - ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption); - ClassDB::bind_method(D_METHOD("find_input_caption", "caption"), &AnimationNodeTransition::find_input_caption); - ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time); ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time); @@ -901,21 +925,13 @@ void AnimationNodeTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeTransition::set_reset); ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeTransition::is_reset); - ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_inputs", PROPERTY_HINT_RANGE, "0,31,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset"), "set_reset", "is_reset"); - - for (int i = 0; i < MAX_INPUTS; i++) { - ADD_PROPERTYI(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_caption", "get_input_caption", i); - ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/auto_advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_as_auto_advance", "is_input_set_as_auto_advance", i); - } + ADD_PROPERTY(PropertyInfo(Variant::INT, "input_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED, "Inputs,input_"), "set_input_count", "get_input_count"); } AnimationNodeTransition::AnimationNodeTransition() { - for (int i = 0; i < MAX_INPUTS; i++) { - inputs[i].name = "state " + itos(i); - } } ///////////////////// diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index a1969bb621..09bf567db7 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -276,16 +276,7 @@ public: class AnimationNodeTransition : public AnimationNodeSync { GDCLASS(AnimationNodeTransition, AnimationNodeSync); - enum { - MAX_INPUTS = 32 - }; - struct InputData { - String name; - bool auto_advance = false; - }; - - InputData inputs[MAX_INPUTS]; - int enabled_inputs = 0; + Vector<bool> input_as_auto_advance; StringName time = "time"; StringName prev_xfading = "prev_xfading"; @@ -301,11 +292,11 @@ class AnimationNodeTransition : public AnimationNodeSync { Ref<Curve> xfade_curve; bool reset = true; - void _update_inputs(); - protected: + bool _get(const StringName &p_path, Variant &r_ret) const; + bool _set(const StringName &p_path, const Variant &p_value); static void _bind_methods(); - void _validate_property(PropertyInfo &p_property) const; + void _get_property_list(List<PropertyInfo> *p_list) const; public: virtual void get_parameter_list(List<PropertyInfo> *r_list) const override; @@ -314,16 +305,14 @@ public: virtual String get_caption() const override; - void set_enabled_inputs(int p_inputs); - int get_enabled_inputs(); + void set_input_count(int p_inputs); + + virtual bool add_input(const String &p_name) override; + virtual void remove_input(int p_index) override; void set_input_as_auto_advance(int p_input, bool p_enable); bool is_input_set_as_auto_advance(int p_input) const; - void set_input_caption(int p_input, const String &p_name); - String get_input_caption(int p_input) const; - int find_input_caption(const String &p_name) const; - void set_xfade_time(double p_fade); double get_xfade_time() const; diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index f630660049..1c1f94c986 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -303,36 +303,21 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_is_external_seeking, p_connections); } -int AnimationNode::get_input_count() const { - return inputs.size(); -} - -String AnimationNode::get_input_name(int p_input) { - ERR_FAIL_INDEX_V(p_input, inputs.size(), String()); - return inputs[p_input].name; -} - String AnimationNode::get_caption() const { String ret = "Node"; GDVIRTUAL_CALL(_get_caption, ret); return ret; } -void AnimationNode::add_input(const String &p_name) { +bool AnimationNode::add_input(const String &p_name) { //root nodes can't add inputs - ERR_FAIL_COND(Object::cast_to<AnimationRootNode>(this) != nullptr); + ERR_FAIL_COND_V(Object::cast_to<AnimationRootNode>(this) != nullptr, false); Input input; - ERR_FAIL_COND(p_name.contains(".") || p_name.contains("/")); + ERR_FAIL_COND_V(p_name.contains(".") || p_name.contains("/"), false); input.name = p_name; inputs.push_back(input); emit_changed(); -} - -void AnimationNode::set_input_name(int p_input, const String &p_name) { - ERR_FAIL_INDEX(p_input, inputs.size()); - ERR_FAIL_COND(p_name.contains(".") || p_name.contains("/")); - inputs.write[p_input].name = p_name; - emit_changed(); + return true; } void AnimationNode::remove_input(int p_index) { @@ -341,6 +326,34 @@ void AnimationNode::remove_input(int p_index) { emit_changed(); } +bool AnimationNode::set_input_name(int p_input, const String &p_name) { + ERR_FAIL_INDEX_V(p_input, inputs.size(), false); + ERR_FAIL_COND_V(p_name.contains(".") || p_name.contains("/"), false); + inputs.write[p_input].name = p_name; + emit_changed(); + return true; +} + +String AnimationNode::get_input_name(int p_input) const { + ERR_FAIL_INDEX_V(p_input, inputs.size(), String()); + return inputs[p_input].name; +} + +int AnimationNode::get_input_count() const { + return inputs.size(); +} + +int AnimationNode::find_input(const String &p_name) const { + int idx = -1; + for (int i = 0; i < inputs.size(); i++) { + if (inputs[i].name == p_name) { + idx = i; + break; + } + } + return idx; +} + double AnimationNode::process(double p_time, bool p_seek, bool p_is_external_seeking) { double ret = 0; GDVIRTUAL_CALL(_process, p_time, p_seek, p_is_external_seeking, ret); @@ -404,11 +417,12 @@ Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) { } void AnimationNode::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count); - ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name); - ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input); ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input); + ClassDB::bind_method(D_METHOD("set_input_name", "input", "name"), &AnimationNode::set_input_name); + ClassDB::bind_method(D_METHOD("get_input_name", "input"), &AnimationNode::get_input_name); + ClassDB::bind_method(D_METHOD("get_input_count"), &AnimationNode::get_input_count); + ClassDB::bind_method(D_METHOD("find_input", "name"), &AnimationNode::find_input); ClassDB::bind_method(D_METHOD("set_filter_path", "path", "enable"), &AnimationNode::set_filter_path); ClassDB::bind_method(D_METHOD("is_path_filtered", "path"), &AnimationNode::is_path_filtered); diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index c54493828f..a6fb4a8430 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -141,12 +141,12 @@ public: virtual double process(double p_time, bool p_seek, bool p_is_external_seeking); virtual String get_caption() const; + virtual bool add_input(const String &p_name); + virtual void remove_input(int p_index); + virtual bool set_input_name(int p_input, const String &p_name); + virtual String get_input_name(int p_input) const; int get_input_count() const; - String get_input_name(int p_input); - - void add_input(const String &p_name); - void set_input_name(int p_input, const String &p_name); - void remove_input(int p_index); + int find_input(const String &p_name) const; void set_filter_path(const NodePath &p_path, bool p_enable); bool is_path_filtered(const NodePath &p_path) const; |