summaryrefslogtreecommitdiff
path: root/scene/animation
diff options
context:
space:
mode:
Diffstat (limited to 'scene/animation')
-rw-r--r--scene/animation/SCsub3
-rw-r--r--scene/animation/animation_blend_tree.cpp76
-rw-r--r--scene/animation/animation_blend_tree.h2
-rw-r--r--scene/animation/animation_node_state_machine.cpp34
-rw-r--r--scene/animation/animation_player.cpp56
-rw-r--r--scene/animation/animation_tree.cpp54
-rw-r--r--scene/animation/animation_tree.h8
-rw-r--r--scene/animation/easing_equations.h405
-rw-r--r--scene/animation/tween.cpp71
-rw-r--r--scene/animation/tween.h10
10 files changed, 591 insertions, 128 deletions
diff --git a/scene/animation/SCsub b/scene/animation/SCsub
index cc33a5af84..d0aa0bc8aa 100644
--- a/scene/animation/SCsub
+++ b/scene/animation/SCsub
@@ -6,11 +6,8 @@ Import("env")
thirdparty_obj = []
-thirdparty_sources = "#thirdparty/misc/easing_equations.cpp"
-
env_thirdparty = env.Clone()
env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
env.scene_sources += thirdparty_obj
# Godot source files
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 049f3483ff..10a66386eb 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -248,27 +248,26 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek) {
if (fade_in > 0) {
blend = time / fade_in;
} else {
- blend = 0; //wtf
+ blend = 0;
}
-
- } else if (!do_start && remaining < fade_out) {
- if (fade_out) {
+ } else if (!do_start && remaining <= fade_out) {
+ if (fade_out > 0) {
blend = (remaining / fade_out);
} else {
- blend = 1.0;
+ blend = 0;
}
} else {
blend = 1.0;
}
- float main_rem;
+ double main_rem;
if (mix == MIX_MODE_ADD) {
main_rem = blend_input(0, p_time, p_seek, 1.0, FILTER_IGNORE, !sync);
} else {
main_rem = blend_input(0, p_time, p_seek, 1.0 - blend, FILTER_BLEND, !sync);
}
- float os_rem = blend_input(1, os_seek ? time : p_time, os_seek, blend, FILTER_PASS, false);
+ double os_rem = blend_input(1, os_seek ? time : p_time, os_seek, blend, FILTER_PASS, false);
if (do_start) {
remaining = os_rem;
@@ -718,7 +717,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek) {
} else { // cross-fading from prev to current
- float blend = xfade ? (prev_xfading / xfade) : 1;
+ float blend = xfade == 0 ? 0 : (prev_xfading / xfade);
if (!p_seek && switched) { //just switched, seek to start of current
@@ -829,9 +828,9 @@ Ref<AnimationNode> AnimationNodeBlendTree::get_node(const StringName &p_name) co
}
StringName AnimationNodeBlendTree::get_node_name(const Ref<AnimationNode> &p_node) const {
- for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
- if (E->get().node == p_node) {
- return E->key();
+ for (const KeyValue<StringName, Node> &E : nodes) {
+ if (E.value.node == p_node) {
+ return E.key;
}
}
@@ -851,8 +850,8 @@ Vector2 AnimationNodeBlendTree::get_node_position(const StringName &p_node) cons
void AnimationNodeBlendTree::get_child_nodes(List<ChildNode> *r_child_nodes) {
Vector<StringName> ns;
- for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
- ns.push_back(E->key());
+ for (const KeyValue<StringName, Node> &E : nodes) {
+ ns.push_back(E.key);
}
ns.sort_custom<StringName::AlphCompare>();
@@ -887,10 +886,10 @@ void AnimationNodeBlendTree::remove_node(const StringName &p_name) {
nodes.erase(p_name);
//erase connections to name
- for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
- for (int i = 0; i < E->get().connections.size(); i++) {
- if (E->get().connections[i] == p_name) {
- E->get().connections.write[i] = StringName();
+ for (KeyValue<StringName, Node> &E : nodes) {
+ for (int i = 0; i < E.value.connections.size(); i++) {
+ if (E.value.connections[i] == p_name) {
+ E.value.connections.write[i] = StringName();
}
}
}
@@ -911,10 +910,10 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN
nodes.erase(p_name);
//rename connections
- for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
- for (int i = 0; i < E->get().connections.size(); i++) {
- if (E->get().connections[i] == p_name) {
- E->get().connections.write[i] = p_new_name;
+ for (KeyValue<StringName, Node> &E : nodes) {
+ for (int i = 0; i < E.value.connections.size(); i++) {
+ if (E.value.connections[i] == p_name) {
+ E.value.connections.write[i] = p_new_name;
}
}
}
@@ -933,9 +932,9 @@ void AnimationNodeBlendTree::connect_node(const StringName &p_input_node, int p_
Ref<AnimationNode> input = nodes[p_input_node].node;
ERR_FAIL_INDEX(p_input_index, nodes[p_input_node].connections.size());
- for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
- for (int i = 0; i < E->get().connections.size(); i++) {
- StringName output = E->get().connections[i];
+ for (KeyValue<StringName, Node> &E : nodes) {
+ for (int i = 0; i < E.value.connections.size(); i++) {
+ StringName output = E.value.connections[i];
ERR_FAIL_COND(output == p_output_node);
}
}
@@ -977,9 +976,9 @@ AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node
return CONNECTION_ERROR_CONNECTION_EXISTS;
}
- for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
- for (int i = 0; i < E->get().connections.size(); i++) {
- StringName output = E->get().connections[i];
+ for (const KeyValue<StringName, Node> &E : nodes) {
+ for (int i = 0; i < E.value.connections.size(); i++) {
+ const StringName output = E.value.connections[i];
if (output == p_output_node) {
return CONNECTION_ERROR_CONNECTION_EXISTS;
}
@@ -989,12 +988,12 @@ AnimationNodeBlendTree::ConnectionError AnimationNodeBlendTree::can_connect_node
}
void AnimationNodeBlendTree::get_node_connections(List<NodeConnection> *r_connections) const {
- for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
- for (int i = 0; i < E->get().connections.size(); i++) {
- StringName output = E->get().connections[i];
+ for (const KeyValue<StringName, Node> &E : nodes) {
+ for (int i = 0; i < E.value.connections.size(); i++) {
+ const StringName output = E.value.connections[i];
if (output != StringName()) {
NodeConnection nc;
- nc.input_node = E->key();
+ nc.input_node = E.key;
nc.input_index = i;
nc.output_node = output;
r_connections->push_back(nc);
@@ -1013,8 +1012,8 @@ double AnimationNodeBlendTree::process(double p_time, bool p_seek) {
}
void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {
- for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
- r_list->push_back(E->key());
+ for (const KeyValue<StringName, Node> &E : nodes) {
+ r_list->push_back(E.key);
}
}
@@ -1105,8 +1104,8 @@ bool AnimationNodeBlendTree::_get(const StringName &p_name, Variant &r_ret) cons
void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) const {
List<StringName> names;
- for (Map<StringName, Node>::Element *E = nodes.front(); E; E = E->next()) {
- names.push_back(E->key());
+ for (const KeyValue<StringName, Node> &E : nodes) {
+ names.push_back(E.key);
}
names.sort_custom<StringName::AlphCompare>();
@@ -1124,6 +1123,7 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons
void AnimationNodeBlendTree::reset_state() {
graph_offset = Vector2();
nodes.clear();
+ _initialize_node_tree();
emit_changed();
emit_signal(SNAME("tree_changed"));
}
@@ -1162,7 +1162,7 @@ void AnimationNodeBlendTree::_bind_methods() {
BIND_CONSTANT(CONNECTION_ERROR_CONNECTION_EXISTS);
}
-AnimationNodeBlendTree::AnimationNodeBlendTree() {
+void AnimationNodeBlendTree::_initialize_node_tree() {
Ref<AnimationNodeOutput> output;
output.instantiate();
Node n;
@@ -1172,5 +1172,9 @@ AnimationNodeBlendTree::AnimationNodeBlendTree() {
nodes["output"] = n;
}
+AnimationNodeBlendTree::AnimationNodeBlendTree() {
+ _initialize_node_tree();
+}
+
AnimationNodeBlendTree::~AnimationNodeBlendTree() {
}
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index 8508aaf71b..258443a999 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -345,6 +345,8 @@ class AnimationNodeBlendTree : public AnimationRootNode {
void _tree_changed();
void _node_changed(const StringName &p_node);
+ void _initialize_node_tree();
+
protected:
static void _bind_methods();
bool _set(const StringName &p_name, const Variant &p_value);
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 9fc1dbd0c6..81ecb50ea0 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -329,11 +329,17 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
} else {
// teleport to start
- path.clear();
- current = start_request;
- playing = true;
- play_start = true;
- start_request = StringName(); //clear start request
+ if (p_state_machine->states.has(start_request)) {
+ path.clear();
+ current = start_request;
+ playing = true;
+ play_start = true;
+ start_request = StringName(); //clear start request
+ } else {
+ StringName node = start_request;
+ start_request = StringName(); //clear start request
+ ERR_FAIL_V_MSG(0, "No such node: '" + node + "'");
+ }
}
}
@@ -571,9 +577,9 @@ Ref<AnimationNode> AnimationNodeStateMachine::get_node(const StringName &p_name)
}
StringName AnimationNodeStateMachine::get_node_name(const Ref<AnimationNode> &p_node) const {
- for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
- if (E->get().node == p_node) {
- return E->key();
+ for (const KeyValue<StringName, State> &E : states) {
+ if (E.value.node == p_node) {
+ return E.key;
}
}
@@ -583,8 +589,8 @@ StringName AnimationNodeStateMachine::get_node_name(const Ref<AnimationNode> &p_
void AnimationNodeStateMachine::get_child_nodes(List<ChildNode> *r_child_nodes) {
Vector<StringName> nodes;
- for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
- nodes.push_back(E->key());
+ for (const KeyValue<StringName, State> &E : states) {
+ nodes.push_back(E.key);
}
nodes.sort_custom<StringName::AlphCompare>();
@@ -674,8 +680,8 @@ void AnimationNodeStateMachine::rename_node(const StringName &p_name, const Stri
void AnimationNodeStateMachine::get_node_list(List<StringName> *r_nodes) const {
List<StringName> nodes;
- for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
- nodes.push_back(E->key());
+ for (const KeyValue<StringName, State> &E : states) {
+ nodes.push_back(E.key);
}
nodes.sort_custom<StringName::AlphCompare>();
@@ -897,8 +903,8 @@ bool AnimationNodeStateMachine::_get(const StringName &p_name, Variant &r_ret) c
void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) const {
List<StringName> names;
- for (Map<StringName, State>::Element *E = states.front(); E; E = E->next()) {
- names.push_back(E->key());
+ for (const KeyValue<StringName, State> &E : states) {
+ names.push_back(E.key);
}
names.sort_custom<StringName::AlphCompare>();
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index f6091f224c..2c8c4ee788 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -37,7 +37,6 @@
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
-#include "editor/editor_settings.h"
#include "scene/2d/skeleton_2d.h"
void AnimatedValuesBackup::update_skeletons() {
@@ -124,8 +123,8 @@ bool AnimationPlayer::_get(const StringName &p_name, Variant &r_ret) const {
} else if (name == "blend_times") {
Vector<BlendKey> keys;
- for (Map<BlendKey, float>::Element *E = blend_times.front(); E; E = E->next()) {
- keys.ordered_insert(E->key());
+ for (const KeyValue<BlendKey, float> &E : blend_times) {
+ keys.ordered_insert(E.key);
}
Array array;
@@ -147,8 +146,8 @@ void AnimationPlayer::_validate_property(PropertyInfo &property) const {
if (property.name == "current_animation") {
List<String> names;
- for (Map<StringName, AnimationData>::Element *E = animation_set.front(); E; E = E->next()) {
- names.push_back(E->key());
+ for (const KeyValue<StringName, AnimationData> &E : animation_set) {
+ names.push_back(E.key);
}
names.sort();
names.push_front("[stop]");
@@ -167,10 +166,10 @@ void AnimationPlayer::_validate_property(PropertyInfo &property) const {
void AnimationPlayer::_get_property_list(List<PropertyInfo> *p_list) const {
List<PropertyInfo> anim_names;
- for (Map<StringName, AnimationData>::Element *E = animation_set.front(); E; E = E->next()) {
- anim_names.push_back(PropertyInfo(Variant::OBJECT, "anims/" + String(E->key()), PROPERTY_HINT_RESOURCE_TYPE, "Animation", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
- if (E->get().next != StringName()) {
- anim_names.push_back(PropertyInfo(Variant::STRING, "next/" + String(E->key()), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ for (const KeyValue<StringName, AnimationData> &E : animation_set) {
+ anim_names.push_back(PropertyInfo(Variant::OBJECT, "anims/" + String(E.key), PROPERTY_HINT_RESOURCE_TYPE, "Animation", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
+ if (E.value.next != StringName()) {
+ anim_names.push_back(PropertyInfo(Variant::STRING, "next/" + String(E.key), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
}
@@ -737,7 +736,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
if (anim->has_loop()) {
at_anim_pos = Math::fposmod(p_time - pos, (double)anim->get_length()); //seek to loop
} else {
- at_anim_pos = MAX((double)anim->get_length(), p_time - pos); //seek to end
+ at_anim_pos = MIN((double)anim->get_length(), p_time - pos); //seek to end
}
if (player->is_playing() || p_seeked) {
@@ -765,6 +764,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
}
} else {
player->play(anim_name);
+ player->seek(0.0, true);
nc->animation_playing = true;
playing_caches.insert(nc);
}
@@ -1018,8 +1018,8 @@ void AnimationPlayer::rename_animation(const StringName &p_name, const StringNam
List<BlendKey> to_erase;
Map<BlendKey, float> to_insert;
- for (Map<BlendKey, float>::Element *E = blend_times.front(); E; E = E->next()) {
- BlendKey bk = E->key();
+ for (const KeyValue<BlendKey, float> &E : blend_times) {
+ BlendKey bk = E.key;
BlendKey new_bk = bk;
bool erase = false;
if (bk.from == p_name) {
@@ -1033,7 +1033,7 @@ void AnimationPlayer::rename_animation(const StringName &p_name, const StringNam
if (erase) {
to_erase.push_back(bk);
- to_insert[new_bk] = E->get();
+ to_insert[new_bk] = E.value;
}
}
@@ -1070,8 +1070,8 @@ Ref<Animation> AnimationPlayer::get_animation(const StringName &p_name) const {
void AnimationPlayer::get_animation_list(List<StringName> *p_animations) const {
List<String> anims;
- for (Map<StringName, AnimationData>::Element *E = animation_set.front(); E; E = E->next()) {
- anims.push_back(E->key());
+ for (const KeyValue<StringName, AnimationData> &E : animation_set) {
+ anims.push_back(E.key);
}
anims.sort();
@@ -1364,8 +1364,8 @@ void AnimationPlayer::clear_caches() {
node_cache_map.clear();
- for (Map<StringName, AnimationData>::Element *E = animation_set.front(); E; E = E->next()) {
- E->get().node_cache.clear();
+ for (KeyValue<StringName, AnimationData> &E : animation_set) {
+ E.value.node_cache.clear();
}
cache_update_size = 0;
@@ -1387,9 +1387,9 @@ bool AnimationPlayer::is_active() const {
}
StringName AnimationPlayer::find_animation(const Ref<Animation> &p_animation) const {
- for (Map<StringName, AnimationData>::Element *E = animation_set.front(); E; E = E->next()) {
- if (E->get().animation == p_animation) {
- return E->key();
+ for (const KeyValue<StringName, AnimationData> &E : animation_set) {
+ if (E.value.animation == p_animation) {
+ return E.key;
}
}
@@ -1492,18 +1492,12 @@ NodePath AnimationPlayer::get_root() const {
}
void AnimationPlayer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
-#ifdef TOOLS_ENABLED
- const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
-#else
- const String quote_style = "\"";
-#endif
-
String pf = p_function;
if (p_idx == 0 && (p_function == "play" || p_function == "play_backwards" || p_function == "remove_animation" || p_function == "has_animation" || p_function == "queue")) {
List<StringName> al;
get_animation_list(&al);
for (const StringName &name : al) {
- r_options->push_back(String(name).quote(quote_style));
+ r_options->push_back(String(name).quote());
}
}
Node::get_argument_options(p_function, p_idx, r_options);
@@ -1544,12 +1538,12 @@ Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values(Node *p_root_o
entry.bone_idx = -1;
backup->entries.push_back(entry);
} else {
- for (Map<StringName, TrackNodeCache::PropertyAnim>::Element *E = nc->property_anim.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, TrackNodeCache::PropertyAnim> &E : nc->property_anim) {
AnimatedValuesBackup::Entry entry;
- entry.object = E->value().object;
- entry.subpath = E->value().subpath;
+ entry.object = E.value.object;
+ entry.subpath = E.value.subpath;
bool valid;
- entry.value = E->value().object->get_indexed(E->value().subpath, &valid);
+ entry.value = E.value.object->get_indexed(E.value.subpath, &valid);
entry.bone_idx = -1;
if (valid) {
backup->entries.push_back(entry);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 543545b90f..9ca8d478b1 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -36,8 +36,9 @@
#include "servers/audio/audio_stream.h"
void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
- if (get_script_instance()) {
- Array parameters = get_script_instance()->call("_get_parameter_list");
+ Array parameters;
+
+ if (GDVIRTUAL_CALL(_get_parameter_list, parameters)) {
for (int i = 0; i < parameters.size(); i++) {
Dictionary d = parameters[i];
ERR_CONTINUE(d.is_empty());
@@ -47,8 +48,9 @@ void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const {
}
Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const {
- if (get_script_instance()) {
- return get_script_instance()->call("_get_parameter_default_value", p_parameter);
+ Variant ret;
+ if (GDVIRTUAL_CALL(_get_parameter_default_value, p_parameter, ret)) {
+ return ret;
}
return Variant();
}
@@ -72,8 +74,8 @@ Variant AnimationNode::get_parameter(const StringName &p_name) const {
}
void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
- if (get_script_instance()) {
- Dictionary cn = get_script_instance()->call("_get_child_nodes");
+ Dictionary cn;
+ if (GDVIRTUAL_CALL(_get_child_nodes, cn)) {
List<Variant> keys;
cn.get_key_list(&keys);
for (const Variant &E : keys) {
@@ -298,8 +300,9 @@ String AnimationNode::get_input_name(int p_input) {
}
String AnimationNode::get_caption() const {
- if (get_script_instance()) {
- return get_script_instance()->call("_get_caption");
+ String ret;
+ if (GDVIRTUAL_CALL(_get_caption, ret)) {
+ return ret;
}
return "Node";
@@ -329,8 +332,9 @@ void AnimationNode::remove_input(int p_index) {
}
double AnimationNode::process(double p_time, bool p_seek) {
- if (get_script_instance()) {
- return get_script_instance()->call("_process", p_time, p_seek);
+ double ret;
+ if (GDVIRTUAL_CALL(_process, p_time, p_seek, ret)) {
+ return ret;
}
return 0;
@@ -357,8 +361,9 @@ bool AnimationNode::is_path_filtered(const NodePath &p_path) const {
}
bool AnimationNode::has_filter() const {
- if (get_script_instance()) {
- return get_script_instance()->call("_has_filter");
+ bool ret;
+ if (GDVIRTUAL_CALL(_has_filter, ret)) {
+ return ret;
}
return false;
@@ -390,8 +395,9 @@ void AnimationNode::_validate_property(PropertyInfo &property) const {
}
Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) {
- if (get_script_instance()) {
- return get_script_instance()->call("_get_child_by_name", p_name);
+ Ref<AnimationNode> ret;
+ if (GDVIRTUAL_CALL(_get_child_by_name, p_name, ret)) {
+ return ret;
}
return Ref<AnimationNode>();
}
@@ -422,17 +428,13 @@ void AnimationNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_filter_enabled", "is_filter_enabled");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "filters", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_filters", "_get_filters");
- BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "_get_child_nodes"));
- BIND_VMETHOD(MethodInfo(Variant::ARRAY, "_get_parameter_list"));
- BIND_VMETHOD(MethodInfo(Variant::OBJECT, "_get_child_by_name", PropertyInfo(Variant::STRING, "name")));
- {
- MethodInfo mi = MethodInfo(Variant::NIL, "_get_parameter_default_value", PropertyInfo(Variant::STRING_NAME, "name"));
- mi.return_val.usage = PROPERTY_USAGE_NIL_IS_VARIANT;
- BIND_VMETHOD(mi);
- }
- BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::FLOAT, "time"), PropertyInfo(Variant::BOOL, "seek")));
- BIND_VMETHOD(MethodInfo(Variant::STRING, "_get_caption"));
- BIND_VMETHOD(MethodInfo(Variant::BOOL, "_has_filter"));
+ GDVIRTUAL_BIND(_get_child_nodes);
+ GDVIRTUAL_BIND(_get_parameter_list);
+ GDVIRTUAL_BIND(_get_child_by_name, "name");
+ GDVIRTUAL_BIND(_get_parameter_default_value, "parameter");
+ GDVIRTUAL_BIND(_process, "time", "seek");
+ GDVIRTUAL_BIND(_get_caption);
+ GDVIRTUAL_BIND(_has_filter);
ADD_SIGNAL(MethodInfo("removed_from_graph"));
@@ -956,7 +958,7 @@ void AnimationTree::_process_graph(real_t p_delta) {
Variant::interpolate(t->value, value, blend, t->value);
- } else if (delta != 0) {
+ } else {
List<int> indices;
a->value_track_get_key_indices(i, time, delta, &indices);
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 59bbc5b4da..1e0267682e 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -112,6 +112,14 @@ protected:
void _set_parent(Object *p_parent);
+ GDVIRTUAL0RC(Dictionary, _get_child_nodes)
+ GDVIRTUAL0RC(Array, _get_parameter_list)
+ GDVIRTUAL1RC(Ref<AnimationNode>, _get_child_by_name, StringName)
+ GDVIRTUAL1RC(Variant, _get_parameter_default_value, StringName)
+ GDVIRTUAL2RC(double, _process, double, bool)
+ GDVIRTUAL0RC(String, _get_caption)
+ GDVIRTUAL0RC(bool, _has_filter)
+
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
diff --git a/scene/animation/easing_equations.h b/scene/animation/easing_equations.h
new file mode 100644
index 0000000000..c38d083b7f
--- /dev/null
+++ b/scene/animation/easing_equations.h
@@ -0,0 +1,405 @@
+/*************************************************************************/
+/* easing_equations.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+/*
+ * Derived from Robert Penner's easing equations: http://robertpenner.com/easing/
+ *
+ * Copyright (c) 2001 Robert Penner
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef EASING_EQUATIONS_H
+#define EASING_EQUATIONS_H
+
+namespace linear {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * t / d + b;
+}
+}; // namespace linear
+
+namespace sine {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return -c * cos(t / d * (Math_PI / 2)) + c + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ return c * sin(t / d * (Math_PI / 2)) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ return -c / 2 * (cos(Math_PI * t / d) - 1) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace sine
+
+namespace quint {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * pow(t / d, 5) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ return c * (pow(t / d - 1, 5) + 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d * 2;
+
+ if (t < 1) {
+ return c / 2 * pow(t, 5) + b;
+ }
+ return c / 2 * (pow(t - 2, 5) + 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace quint
+
+namespace quart {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * pow(t / d, 4) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ return -c * (pow(t / d - 1, 4) - 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d * 2;
+
+ if (t < 1) {
+ return c / 2 * pow(t, 4) + b;
+ }
+ return -c / 2 * (pow(t - 2, 4) - 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace quart
+
+namespace quad {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c * pow(t / d, 2) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ t /= d;
+ return -c * t * (t - 2) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d * 2;
+
+ if (t < 1) {
+ return c / 2 * pow(t, 2) + b;
+ }
+ return -c / 2 * ((t - 1) * (t - 3) - 1) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace quad
+
+namespace expo {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) {
+ return b;
+ }
+ return c * pow(2, 10 * (t / d - 1)) + b - c * 0.001;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == d) {
+ return b + c;
+ }
+ return c * 1.001 * (-pow(2, -10 * t / d) + 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) {
+ return b;
+ }
+
+ if (t == d) {
+ return b + c;
+ }
+
+ t = t / d * 2;
+
+ if (t < 1) {
+ return c / 2 * pow(2, 10 * (t - 1)) + b - c * 0.0005;
+ }
+ return c / 2 * 1.0005 * (-pow(2, -10 * (t - 1)) + 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace expo
+
+namespace elastic {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) {
+ return b;
+ }
+
+ t /= d;
+ if (t == 1) {
+ return b + c;
+ }
+
+ t -= 1;
+ float p = d * 0.3f;
+ float a = c * pow(2, 10 * t);
+ float s = p / 4;
+
+ return -(a * sin((t * d - s) * (2 * Math_PI) / p)) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) {
+ return b;
+ }
+
+ t /= d;
+ if (t == 1) {
+ return b + c;
+ }
+
+ float p = d * 0.3f;
+ float s = p / 4;
+
+ return (c * pow(2, -10 * t) * sin((t * d - s) * (2 * Math_PI) / p) + c + b);
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ if (t == 0) {
+ return b;
+ }
+
+ if ((t /= d / 2) == 2) {
+ return b + c;
+ }
+
+ float p = d * (0.3f * 1.5f);
+ float a = c;
+ float s = p / 4;
+
+ if (t < 1) {
+ t -= 1;
+ a *= pow(2, 10 * t);
+ return -0.5f * (a * sin((t * d - s) * (2 * Math_PI) / p)) + b;
+ }
+
+ t -= 1;
+ a *= pow(2, -10 * t);
+ return a * sin((t * d - s) * (2 * Math_PI) / p) * 0.5f + c + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace elastic
+
+namespace cubic {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ t /= d;
+ return c * t * t * t + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d - 1;
+ return c * (t * t * t + 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t /= d / 2;
+ if (t < 1) {
+ return c / 2 * t * t * t + b;
+ }
+
+ t -= 2;
+ return c / 2 * (t * t * t + 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace cubic
+
+namespace circ {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ t /= d;
+ return -c * (sqrt(1 - t * t) - 1) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ t = t / d - 1;
+ return c * sqrt(1 - t * t) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ t /= d / 2;
+ if (t < 1) {
+ return -c / 2 * (sqrt(1 - t * t) - 1) + b;
+ }
+
+ t -= 2;
+ return c / 2 * (sqrt(1 - t * t) + 1) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace circ
+
+namespace bounce {
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ t /= d;
+
+ if (t < (1 / 2.75f)) {
+ return c * (7.5625f * t * t) + b;
+ }
+
+ if (t < (2 / 2.75f)) {
+ t -= 1.5f / 2.75f;
+ return c * (7.5625f * t * t + 0.75f) + b;
+ }
+
+ if (t < (2.5 / 2.75)) {
+ t -= 2.25f / 2.75f;
+ return c * (7.5625f * t * t + 0.9375f) + b;
+ }
+
+ t -= 2.625f / 2.75f;
+ return c * (7.5625f * t * t + 0.984375f) + b;
+}
+
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ return c - out(d - t, 0, c, d) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return in(t * 2, b, c / 2, d);
+ }
+ return out(t * 2 - d, b + c / 2, c / 2, d);
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace bounce
+
+namespace back {
+static real_t in(real_t t, real_t b, real_t c, real_t d) {
+ float s = 1.70158f;
+ t /= d;
+
+ return c * t * t * ((s + 1) * t - s) + b;
+}
+
+static real_t out(real_t t, real_t b, real_t c, real_t d) {
+ float s = 1.70158f;
+ t = t / d - 1;
+
+ return c * (t * t * ((s + 1) * t + s) + 1) + b;
+}
+
+static real_t in_out(real_t t, real_t b, real_t c, real_t d) {
+ float s = 1.70158f * 1.525f;
+ t /= d / 2;
+
+ if (t < 1) {
+ return c / 2 * (t * t * ((s + 1) * t - s)) + b;
+ }
+
+ t -= 2;
+ return c / 2 * (t * t * ((s + 1) * t + s) + 2) + b;
+}
+
+static real_t out_in(real_t t, real_t b, real_t c, real_t d) {
+ if (t < d / 2) {
+ return out(t * 2, b, c / 2, d);
+ }
+ return in(t * 2 - d, b + c / 2, c / 2, d);
+}
+}; // namespace back
+
+#endif
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 542011618d..c43b83747b 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -30,12 +30,31 @@
#include "tween.h"
+#include "scene/animation/easing_equations.h"
#include "scene/main/node.h"
+Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = {
+ { &linear::in, &linear::in, &linear::in, &linear::in }, // Linear is the same for each easing.
+ { &sine::in, &sine::out, &sine::in_out, &sine::out_in },
+ { &quint::in, &quint::out, &quint::in_out, &quint::out_in },
+ { &quart::in, &quart::out, &quart::in_out, &quart::out_in },
+ { &quad::in, &quad::out, &quad::in_out, &quad::out_in },
+ { &expo::in, &expo::out, &expo::in_out, &expo::out_in },
+ { &elastic::in, &elastic::out, &elastic::in_out, &elastic::out_in },
+ { &cubic::in, &cubic::out, &cubic::in_out, &cubic::out_in },
+ { &circ::in, &circ::out, &circ::in_out, &circ::out_in },
+ { &bounce::in, &bounce::out, &bounce::in_out, &bounce::out_in },
+ { &back::in, &back::out, &back::in_out, &back::out_in },
+};
+
void Tweener::set_tween(Ref<Tween> p_tween) {
tween = p_tween;
}
+void Tweener::clear_tween() {
+ tween.unref();
+}
+
void Tweener::_bind_methods() {
ADD_SIGNAL(MethodInfo("finished"));
}
@@ -53,16 +72,21 @@ void Tween::start_tweeners() {
Ref<PropertyTweener> Tween::tween_property(Object *p_target, NodePath p_property, Variant p_to, float p_duration) {
ERR_FAIL_NULL_V(p_target, nullptr);
- ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners.");
+ ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
+#ifdef DEBUG_ENABLED
+ Variant::Type property_type = p_target->get_indexed(p_property.get_as_property_path().get_subnames()).get_type();
+ ERR_FAIL_COND_V_MSG(property_type != p_to.get_type(), Ref<PropertyTweener>(), "Type mismatch between property and final value: " + Variant::get_type_name(property_type) + " and " + Variant::get_type_name(p_to.get_type()));
+#endif
+
Ref<PropertyTweener> tweener = memnew(PropertyTweener(p_target, p_property, p_to, p_duration));
append(tweener);
return tweener;
}
Ref<IntervalTweener> Tween::tween_interval(float p_time) {
- ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners.");
+ ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
Ref<IntervalTweener> tweener = memnew(IntervalTweener(p_time));
@@ -71,7 +95,7 @@ Ref<IntervalTweener> Tween::tween_interval(float p_time) {
}
Ref<CallbackTweener> Tween::tween_callback(Callable p_callback) {
- ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners.");
+ ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
Ref<CallbackTweener> tweener = memnew(CallbackTweener(p_callback));
@@ -79,8 +103,8 @@ Ref<CallbackTweener> Tween::tween_callback(Callable p_callback) {
return tweener;
}
-Ref<MethodTweener> Tween::tween_method(Callable p_callback, float p_from, float p_to, float p_duration) {
- ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners.");
+Ref<MethodTweener> Tween::tween_method(Callable p_callback, Variant p_from, Variant p_to, float p_duration) {
+ ERR_FAIL_COND_V_MSG(!valid, nullptr, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
Ref<MethodTweener> tweener = memnew(MethodTweener(p_callback, p_from, p_to, p_duration));
@@ -88,9 +112,7 @@ Ref<MethodTweener> Tween::tween_method(Callable p_callback, float p_from, float
return tweener;
}
-Ref<Tween> Tween::append(Ref<Tweener> p_tweener) {
- ERR_FAIL_COND_V_MSG(invalid, nullptr, "Tween was created outside the scene tree, can't use Tweeners.");
- ERR_FAIL_COND_V_MSG(started, nullptr, "Can't append to a Tween that has started. Use stop() first.");
+void Tween::append(Ref<Tweener> p_tweener) {
p_tweener->set_tween(this);
if (parallel_enabled) {
@@ -102,8 +124,6 @@ Ref<Tween> Tween::append(Ref<Tweener> p_tweener) {
tweeners.resize(current_step + 1);
tweeners.write[current_step].push_back(p_tweener);
-
- return this;
}
void Tween::stop() {
@@ -117,7 +137,7 @@ void Tween::pause() {
}
void Tween::play() {
- ERR_FAIL_COND_MSG(invalid, "Tween invalid, can't play.");
+ ERR_FAIL_COND_MSG(!valid, "Tween invalid. Either finished or created outside scene tree.");
ERR_FAIL_COND_MSG(dead, "Can't play finished Tween, use stop() first to reset its state.");
running = true;
}
@@ -132,11 +152,22 @@ bool Tween::is_running() {
}
void Tween::set_valid(bool p_valid) {
- invalid = !p_valid;
+ valid = p_valid;
}
bool Tween::is_valid() {
- return invalid;
+ return valid;
+}
+
+void Tween::clear() {
+ valid = false;
+
+ for (List<Ref<Tweener>> &step : tweeners) {
+ for (Ref<Tweener> &tweener : step) {
+ tweener->clear_tween();
+ }
+ }
+ tweeners.clear();
}
Ref<Tween> Tween::bind_node(Node *p_node) {
@@ -301,6 +332,16 @@ bool Tween::should_pause() {
return pause_mode != TWEEN_PAUSE_PROCESS;
}
+real_t Tween::run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t p_time, real_t p_initial, real_t p_delta, real_t p_duration) {
+ if (p_duration == 0) {
+ // Special case to avoid dividing by 0 in equations.
+ return p_initial + p_delta;
+ }
+
+ interpolater func = interpolaters[p_trans_type][p_ease_type];
+ return func(p_time, p_initial, p_delta, p_duration);
+}
+
Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, float p_time, float p_duration, TransitionType p_trans, EaseType p_ease) {
ERR_FAIL_INDEX_V(p_trans, TransitionType::TRANS_MAX, Variant());
ERR_FAIL_INDEX_V(p_ease, EaseType::EASE_MAX, Variant());
@@ -485,6 +526,8 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, f
}
Variant Tween::calculate_delta_value(Variant p_intial_val, Variant p_final_val) {
+ ERR_FAIL_COND_V_MSG(p_intial_val.get_type() != p_final_val.get_type(), p_intial_val, "Type mismatch between initial and final value: " + Variant::get_type_name(p_intial_val.get_type()) + " and " + Variant::get_type_name(p_final_val.get_type()));
+
switch (p_intial_val.get_type()) {
case Variant::BOOL: {
return (int)p_final_val - (int)p_intial_val;
@@ -877,7 +920,7 @@ void MethodTweener::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_ease", "ease"), &MethodTweener::set_ease);
}
-MethodTweener::MethodTweener(Callable p_callback, float p_from, float p_to, float p_duration) {
+MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration) {
callback = p_callback;
initial_val = p_from;
delta_val = tween->calculate_delta_value(p_from, p_to);
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 947cdb7c2d..6a48d332b8 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -43,6 +43,7 @@ public:
virtual void set_tween(Ref<Tween> p_tween);
virtual void start() = 0;
virtual bool step(float &r_delta) = 0;
+ void clear_tween();
protected:
static void _bind_methods();
@@ -111,7 +112,7 @@ private:
bool started = false;
bool running = true;
bool dead = false;
- bool invalid = true;
+ bool valid = false;
bool default_parallel = false;
bool parallel_enabled = false;
@@ -127,8 +128,8 @@ public:
Ref<PropertyTweener> tween_property(Object *p_target, NodePath p_property, Variant p_to, float p_duration);
Ref<IntervalTweener> tween_interval(float p_time);
Ref<CallbackTweener> tween_callback(Callable p_callback);
- Ref<MethodTweener> tween_method(Callable p_callback, float p_from, float p_to, float p_duration);
- Ref<Tween> append(Ref<Tweener> p_tweener);
+ Ref<MethodTweener> tween_method(Callable p_callback, Variant p_from, Variant p_to, float p_duration);
+ void append(Ref<Tweener> p_tweener);
bool custom_step(float p_delta);
void stop();
@@ -139,6 +140,7 @@ public:
bool is_running();
void set_valid(bool p_valid);
bool is_valid();
+ void clear();
Ref<Tween> bind_node(Node *p_node);
Ref<Tween> set_process_mode(TweenProcessMode p_mode);
@@ -256,7 +258,7 @@ public:
void start() override;
bool step(float &r_delta) override;
- MethodTweener(Callable p_callback, float p_from, float p_to, float p_duration);
+ MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration);
MethodTweener();
protected: