summaryrefslogtreecommitdiff
path: root/scene/animation/animation_player.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/animation/animation_player.cpp')
-rw-r--r--scene/animation/animation_player.cpp154
1 files changed, 92 insertions, 62 deletions
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 4714282347..77d82990d1 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -143,8 +143,8 @@ bool AnimationPlayer::_get(const StringName &p_name, Variant &r_ret) const {
} else if (name.begins_with("libraries")) {
Dictionary d;
- for (uint32_t i = 0; i < animation_libraries.size(); i++) {
- d[animation_libraries[i].name] = animation_libraries[i].library;
+ for (const AnimationLibraryData &lib : animation_libraries) {
+ d[lib.name] = lib.library;
}
r_ret = d;
@@ -451,6 +451,15 @@ static void _call_object(Object *p_object, const StringName &p_method, const Vec
}
}
+Variant AnimationPlayer::post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) {
+ Variant res;
+ if (GDVIRTUAL_CALL(_post_process_key_value, p_anim, p_track, p_value, const_cast<Object *>(p_object), p_object_idx, res)) {
+ return res;
+ }
+
+ return _post_process_key_value(p_anim, p_track, p_value, p_object, p_object_idx);
+}
+
Variant AnimationPlayer::_post_process_key_value(const Ref<Animation> &p_anim, int p_track, Variant p_value, const Object *p_object, int p_object_idx) {
switch (p_anim->track_get_type(p_track)) {
#ifndef _3D_DISABLED
@@ -473,7 +482,9 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
ERR_FAIL_COND(p_anim->node_cache.size() != p_anim->animation->get_track_count());
Animation *a = p_anim->animation.operator->();
+#ifdef TOOLS_ENABLED
bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint();
+#endif // TOOLS_ENABLED
bool backward = signbit(p_delta);
for (int i = 0; i < a->get_track_count(); i++) {
@@ -512,7 +523,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
if (err != OK) {
continue;
}
- loc = _post_process_key_value(a, i, loc, nc->node_3d, nc->bone_idx);
+ loc = post_process_key_value(a, i, loc, nc->node_3d, nc->bone_idx);
if (nc->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
@@ -540,7 +551,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
if (err != OK) {
continue;
}
- rot = _post_process_key_value(a, i, rot, nc->node_3d, nc->bone_idx);
+ rot = post_process_key_value(a, i, rot, nc->node_3d, nc->bone_idx);
if (nc->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
@@ -568,7 +579,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
if (err != OK) {
continue;
}
- scale = _post_process_key_value(a, i, scale, nc->node_3d, nc->bone_idx);
+ scale = post_process_key_value(a, i, scale, nc->node_3d, nc->bone_idx);
if (nc->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
@@ -596,7 +607,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
if (err != OK) {
continue;
}
- blend = _post_process_key_value(a, i, blend, nc->node_blend_shape, nc->blend_shape_idx);
+ blend = post_process_key_value(a, i, blend, nc->node_blend_shape, nc->blend_shape_idx);
if (nc->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_size >= NODE_CACHE_UPDATE_MAX);
@@ -649,7 +660,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
if (p_time < first_key_time) {
double c = Math::ease(p_time / first_key_time, transition);
Variant first_value = a->track_get_key_value(i, first_key);
- first_value = _post_process_key_value(a, i, first_value, nc->node);
+ first_value = post_process_key_value(a, i, first_value, nc->node);
Variant interp_value = Animation::interpolate_variant(pa->capture, first_value, c);
if (pa->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_prop_size >= NODE_CACHE_UPDATE_MAX);
@@ -670,7 +681,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
if (value == Variant()) {
continue;
}
- value = _post_process_key_value(a, i, value, nc->node);
+ value = post_process_key_value(a, i, value, nc->node);
if (pa->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_prop_size >= NODE_CACHE_UPDATE_MAX);
@@ -701,7 +712,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
for (int &F : indices) {
Variant value = a->track_get_key_value(i, F);
- value = _post_process_key_value(a, i, value, nc->node);
+ value = post_process_key_value(a, i, value, nc->node);
switch (pa->special) {
case SP_NONE: {
bool valid;
@@ -745,11 +756,13 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} break;
case Animation::TYPE_METHOD: {
- if (!nc->node) {
+#ifdef TOOLS_ENABLED
+ if (!can_call) {
continue;
}
- if (!p_is_current) {
- break;
+#endif // TOOLS_ENABLED
+ if (!p_is_current || !nc->node || is_stopping) {
+ continue;
}
List<int> indices;
@@ -772,16 +785,12 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
for (int &E : indices) {
StringName method = a->method_track_get_name(i, E);
Vector<Variant> params = a->method_track_get_params(i, E);
-
#ifdef DEBUG_ENABLED
if (!nc->node->has_method(method)) {
ERR_PRINT("Invalid method call '" + method + "'. '" + a->get_name() + "' at node '" + get_path() + "'.");
}
#endif
-
- if (can_call) {
- _call_object(nc->node, method, params, method_call_mode == ANIMATION_METHOD_CALL_DEFERRED);
- }
+ _call_object(nc->node, method, params, method_call_mode == ANIMATION_METHOD_CALL_DEFERRED);
}
} break;
@@ -796,7 +805,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
TrackNodeCache::BezierAnim *ba = &E->value;
real_t bezier = a->bezier_track_interpolate(i, p_time);
- bezier = _post_process_key_value(a, i, bezier, nc->node);
+ bezier = post_process_key_value(a, i, bezier, nc->node);
if (ba->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_bezier_size >= NODE_CACHE_UPDATE_MAX);
cache_update_bezier[cache_update_bezier_size++] = ba;
@@ -808,12 +817,16 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} break;
case Animation::TYPE_AUDIO: {
- if (!nc->node) {
+ if (!nc->node || is_stopping) {
continue;
}
if (p_seeked) {
- //find whatever should be playing
+#ifdef TOOLS_ENABLED
+ if (!can_call) {
+ continue; // To avoid spamming the preview in editor.
+ }
+#endif // TOOLS_ENABLED
int idx = a->track_find_key(i, p_time);
if (idx < 0) {
continue;
@@ -915,6 +928,10 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} break;
case Animation::TYPE_ANIMATION: {
+ if (is_stopping) {
+ continue;
+ }
+
AnimationPlayer *player = Object::cast_to<AnimationPlayer>(nc->node);
if (!player) {
continue;
@@ -1265,13 +1282,13 @@ void AnimationPlayer::_animation_set_cache_update() {
bool clear_cache_needed = false;
// Update changed and add otherwise
- for (uint32_t i = 0; i < animation_libraries.size(); i++) {
- for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[i].library->animations) {
- StringName key = animation_libraries[i].name == StringName() ? K.key : StringName(String(animation_libraries[i].name) + "/" + String(K.key));
+ for (const AnimationLibraryData &lib : animation_libraries) {
+ for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) {
+ StringName key = lib.name == StringName() ? K.key : StringName(String(lib.name) + "/" + String(K.key));
if (!animation_set.has(key)) {
AnimationData ad;
ad.animation = K.value;
- ad.animation_library = animation_libraries[i].name;
+ ad.animation_library = lib.name;
ad.name = key;
ad.last_update = animation_set_update_pass;
animation_set.insert(ad.name, ad);
@@ -1279,11 +1296,11 @@ void AnimationPlayer::_animation_set_cache_update() {
AnimationData &ad = animation_set[key];
if (ad.last_update != animation_set_update_pass) {
// Was not updated, update. If the animation is duplicated, the second one will be ignored.
- if (ad.animation != K.value || ad.animation_library != animation_libraries[i].name) {
+ if (ad.animation != K.value || ad.animation_library != lib.name) {
// Animation changed, update and clear caches.
clear_cache_needed = true;
ad.animation = K.value;
- ad.animation_library = animation_libraries[i].name;
+ ad.animation_library = lib.name;
}
ad.last_update = animation_set_update_pass;
@@ -1401,11 +1418,11 @@ Error AnimationPlayer::add_animation_library(const StringName &p_name, const Ref
int insert_pos = 0;
- for (uint32_t i = 0; i < animation_libraries.size(); i++) {
- ERR_FAIL_COND_V_MSG(animation_libraries[i].name == p_name, ERR_ALREADY_EXISTS, "Can't add animation library twice with name: " + String(p_name));
- ERR_FAIL_COND_V_MSG(animation_libraries[i].library == p_animation_library, ERR_ALREADY_EXISTS, "Can't add animation library twice (adding as '" + p_name.operator String() + "', exists as '" + animation_libraries[i].name.operator String() + "'.");
+ for (const AnimationLibraryData &lib : animation_libraries) {
+ ERR_FAIL_COND_V_MSG(lib.name == p_name, ERR_ALREADY_EXISTS, "Can't add animation library twice with name: " + String(p_name));
+ ERR_FAIL_COND_V_MSG(lib.library == p_animation_library, ERR_ALREADY_EXISTS, "Can't add animation library twice (adding as '" + p_name.operator String() + "', exists as '" + lib.name.operator String() + "'.");
- if (animation_libraries[i].name.operator String() >= p_name.operator String()) {
+ if (lib.name.operator String() >= p_name.operator String()) {
break;
}
@@ -1464,21 +1481,21 @@ void AnimationPlayer::rename_animation_library(const StringName &p_name, const S
#endif
bool found = false;
- for (uint32_t i = 0; i < animation_libraries.size(); i++) {
- ERR_FAIL_COND_MSG(animation_libraries[i].name == p_new_name, "Can't rename animation library to another existing name: " + String(p_new_name));
- if (animation_libraries[i].name == p_name) {
+ for (AnimationLibraryData &lib : animation_libraries) {
+ ERR_FAIL_COND_MSG(lib.name == p_new_name, "Can't rename animation library to another existing name: " + String(p_new_name));
+ if (lib.name == p_name) {
found = true;
- animation_libraries[i].name = p_new_name;
+ lib.name = p_new_name;
// rename connections
- animation_libraries[i].library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added));
- animation_libraries[i].library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed));
- animation_libraries[i].library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed));
+ lib.library->disconnect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added));
+ lib.library->disconnect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed));
+ lib.library->disconnect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed));
- animation_libraries[i].library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_new_name));
- animation_libraries[i].library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_new_name));
- animation_libraries[i].library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_new_name));
+ lib.library->connect(SNAME("animation_added"), callable_mp(this, &AnimationPlayer::_animation_added).bind(p_new_name));
+ lib.library->connect(SNAME("animation_removed"), callable_mp(this, &AnimationPlayer::_animation_removed).bind(p_new_name));
+ lib.library->connect(SNAME("animation_renamed"), callable_mp(this, &AnimationPlayer::_animation_renamed).bind(p_new_name));
- for (const KeyValue<StringName, Ref<Animation>> &K : animation_libraries[i].library->animations) {
+ for (const KeyValue<StringName, Ref<Animation>> &K : lib.library->animations) {
StringName old_name = p_name == StringName() ? K.key : StringName(String(p_name) + "/" + String(K.key));
StringName new_name = p_new_name == StringName() ? K.key : StringName(String(p_new_name) + "/" + String(K.key));
_rename_animation(old_name, new_name);
@@ -1498,8 +1515,8 @@ void AnimationPlayer::rename_animation_library(const StringName &p_name, const S
}
bool AnimationPlayer::has_animation_library(const StringName &p_name) const {
- for (uint32_t i = 0; i < animation_libraries.size(); i++) {
- if (animation_libraries[i].name == p_name) {
+ for (const AnimationLibraryData &lib : animation_libraries) {
+ if (lib.name == p_name) {
return true;
}
}
@@ -1508,9 +1525,9 @@ bool AnimationPlayer::has_animation_library(const StringName &p_name) const {
}
Ref<AnimationLibrary> AnimationPlayer::get_animation_library(const StringName &p_name) const {
- for (uint32_t i = 0; i < animation_libraries.size(); i++) {
- if (animation_libraries[i].name == p_name) {
- return animation_libraries[i].library;
+ for (const AnimationLibraryData &lib : animation_libraries) {
+ if (lib.name == p_name) {
+ return lib.library;
}
}
ERR_FAIL_V(Ref<AnimationLibrary>());
@@ -1518,15 +1535,15 @@ Ref<AnimationLibrary> AnimationPlayer::get_animation_library(const StringName &p
TypedArray<StringName> AnimationPlayer::_get_animation_library_list() const {
TypedArray<StringName> ret;
- for (uint32_t i = 0; i < animation_libraries.size(); i++) {
- ret.push_back(animation_libraries[i].name);
+ for (const AnimationLibraryData &lib : animation_libraries) {
+ ret.push_back(lib.name);
}
return ret;
}
void AnimationPlayer::get_animation_library_list(List<StringName> *p_libraries) const {
- for (uint32_t i = 0; i < animation_libraries.size(); i++) {
- p_libraries->push_back(animation_libraries[i].name);
+ for (const AnimationLibraryData &lib : animation_libraries) {
+ p_libraries->push_back(lib.name);
}
}
@@ -1658,7 +1675,7 @@ void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, floa
}
if (get_current_animation() != p_name) {
- _stop_playing_caches();
+ _stop_playing_caches(false);
}
c.current.from = &animation_set[name];
@@ -1732,11 +1749,11 @@ String AnimationPlayer::get_assigned_animation() const {
}
void AnimationPlayer::pause() {
- _stop_internal(false);
+ _stop_internal(false, false);
}
-void AnimationPlayer::stop() {
- _stop_internal(true);
+void AnimationPlayer::stop(bool p_keep_state) {
+ _stop_internal(true, p_keep_state);
}
void AnimationPlayer::set_speed_scale(float p_speed) {
@@ -1808,7 +1825,7 @@ void AnimationPlayer::_animation_changed(const StringName &p_name) {
}
}
-void AnimationPlayer::_stop_playing_caches() {
+void AnimationPlayer::_stop_playing_caches(bool p_reset) {
for (TrackNodeCache *E : playing_caches) {
if (E->node && E->audio_playing) {
E->node->call(SNAME("stop"));
@@ -1818,7 +1835,12 @@ void AnimationPlayer::_stop_playing_caches() {
if (!player) {
continue;
}
- player->stop();
+
+ if (p_reset) {
+ player->stop();
+ } else {
+ player->pause();
+ }
}
}
@@ -1830,7 +1852,7 @@ void AnimationPlayer::_node_removed(Node *p_node) {
}
void AnimationPlayer::clear_caches() {
- _stop_playing_caches();
+ _stop_playing_caches(true);
node_cache_map.clear();
@@ -1951,14 +1973,20 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) {
processing = p_process;
}
-void AnimationPlayer::_stop_internal(bool p_reset) {
- _stop_playing_caches();
+void AnimationPlayer::_stop_internal(bool p_reset, bool p_keep_state) {
+ _stop_playing_caches(p_reset);
Playback &c = playback;
c.blend.clear();
if (p_reset) {
+ if (p_keep_state) {
+ c.current.pos = 0;
+ } else {
+ is_stopping = true;
+ seek(0, true);
+ is_stopping = false;
+ }
c.current.from = nullptr;
c.current.speed_scale = 1;
- c.current.pos = 0;
}
_set_process(false);
queued.clear();
@@ -2089,7 +2117,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) {
Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values();
old_values->restore();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Animation Apply Reset"));
ur->add_do_method(new_values.ptr(), "restore");
ur->add_undo_method(old_values.ptr(), "restore");
@@ -2128,7 +2156,7 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("play", "name", "custom_blend", "custom_speed", "from_end"), &AnimationPlayer::play, DEFVAL(""), DEFVAL(-1), DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("play_backwards", "name", "custom_blend"), &AnimationPlayer::play_backwards, DEFVAL(""), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("pause"), &AnimationPlayer::pause);
- ClassDB::bind_method(D_METHOD("stop"), &AnimationPlayer::stop);
+ ClassDB::bind_method(D_METHOD("stop", "keep_state"), &AnimationPlayer::stop, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_playing"), &AnimationPlayer::is_playing);
ClassDB::bind_method(D_METHOD("set_current_animation", "anim"), &AnimationPlayer::set_current_animation);
@@ -2175,6 +2203,8 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("seek", "seconds", "update"), &AnimationPlayer::seek, DEFVAL(false));
ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationPlayer::advance);
+ GDVIRTUAL_BIND(_post_process_key_value, "animation", "track", "value", "object", "object_idx");
+
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root", "get_root");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "current_animation", PROPERTY_HINT_ENUM, "", PROPERTY_USAGE_EDITOR), "set_current_animation", "get_current_animation");
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "assigned_animation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_assigned_animation", "get_assigned_animation");