summaryrefslogtreecommitdiff
path: root/scene/animation
diff options
context:
space:
mode:
Diffstat (limited to 'scene/animation')
-rw-r--r--scene/animation/animation_player.cpp75
-rw-r--r--scene/animation/animation_tree.cpp6
2 files changed, 47 insertions, 34 deletions
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index f7baa7facc..cc6fadd9b2 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -956,8 +956,8 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
}
if (player->is_playing()) {
- player->play(anim_name);
player->seek(at_anim_pos);
+ player->play(anim_name);
nc->animation_playing = true;
playing_caches.insert(nc);
} else {
@@ -985,8 +985,8 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
nc->animation_playing = false;
}
} else {
+ player->seek(0.0);
player->play(anim_name);
- player->seek(0.0, true);
nc->animation_playing = true;
playing_caches.insert(nc);
}
@@ -1001,6 +1001,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
void AnimationPlayer::_animation_process_data(PlaybackData &cd, double p_delta, float p_blend, bool p_seeked, bool p_started) {
double delta = p_delta * speed_scale * cd.speed_scale;
double next_pos = cd.pos + delta;
+ bool backwards = signbit(delta); // Negative zero means playing backwards too.
real_t len = cd.from->animation->get_length();
Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE;
@@ -1012,23 +1013,7 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, double p_delta,
} else if (next_pos > len) {
next_pos = len;
}
-
- bool backwards = signbit(delta); // Negative zero means playing backwards too
- delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here)
-
- if (&cd == &playback.current) {
- if (!backwards && cd.pos <= len && next_pos == len) {
- //playback finished
- end_reached = true;
- end_notify = cd.pos < len; // Notify only if not already at the end
- }
-
- if (backwards && cd.pos >= 0 && next_pos == 0) {
- //playback finished
- end_reached = true;
- end_notify = cd.pos > 0; // Notify only if not already at the beginning
- }
- }
+ delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here).
} break;
case Animation::LOOP_LINEAR: {
@@ -1057,8 +1042,28 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, double p_delta,
break;
}
- _animation_process_animation(cd.from, cd.pos, next_pos, delta, p_blend, &cd == &playback.current, p_seeked, p_started, looped_flag);
+ double prev_pos = cd.pos; // The animation may be changed during process, so it is safer that the state is changed before process.
cd.pos = next_pos;
+
+ AnimationData *prev_from = cd.from;
+ _animation_process_animation(cd.from, prev_pos, cd.pos, delta, p_blend, &cd == &playback.current, p_seeked, p_started, looped_flag);
+
+ // End detection.
+ if (cd.from->animation->get_loop_mode() == Animation::LOOP_NONE) {
+ if (prev_from != playback.current.from) {
+ return; // Animation has been changed in the process (may be caused by method track), abort process.
+ }
+ if (!backwards && prev_pos <= len && next_pos == len) {
+ // Playback finished.
+ end_reached = true;
+ end_notify = prev_pos < len; // Notify only if not already at the end.
+ }
+ if (backwards && prev_pos >= 0 && next_pos == 0) {
+ // Playback finished.
+ end_reached = true;
+ end_notify = prev_pos > 0; // Notify only if not already at the beginning.
+ }
+ }
}
void AnimationPlayer::_animation_process2(double p_delta, bool p_started) {
@@ -1066,23 +1071,25 @@ void AnimationPlayer::_animation_process2(double p_delta, bool p_started) {
accum_pass++;
- _animation_process_data(c.current, p_delta, 1.0f, c.seeked, p_started);
+ bool seeked = c.seeked; // The animation may be changed during process, so it is safer that the state is changed before process.
if (p_delta != 0) {
c.seeked = false;
}
+ _animation_process_data(c.current, p_delta, 1.0f, seeked, p_started);
+
List<Blend>::Element *prev = nullptr;
for (List<Blend>::Element *E = c.blend.back(); E; E = prev) {
Blend &b = E->get();
float blend = b.blend_left / b.blend_time;
- _animation_process_data(b.data, p_delta, blend, false, false);
-
b.blend_left -= Math::absf(speed_scale * p_delta);
-
prev = E->prev();
if (b.blend_left < 0) {
c.blend.erase(E);
}
+ // The effect of animation changes during blending is unknown...
+ // In that case, we recommends to use method call mode "deferred", not "immediate".
+ _animation_process_data(b.data, p_delta, blend, false, false);
}
}
@@ -1123,8 +1130,6 @@ void AnimationPlayer::_animation_update_transforms() {
}
}
- cache_update_size = 0;
-
for (int i = 0; i < cache_update_prop_size; i++) {
TrackNodeCache::PropertyAnim *pa = cache_update_prop[i];
@@ -1186,29 +1191,35 @@ void AnimationPlayer::_animation_update_transforms() {
}
}
- cache_update_prop_size = 0;
-
for (int i = 0; i < cache_update_bezier_size; i++) {
TrackNodeCache::BezierAnim *ba = cache_update_bezier[i];
ERR_CONTINUE(ba->accum_pass != accum_pass);
ba->object->set_indexed(ba->bezier_property, ba->bezier_accum);
}
-
- cache_update_bezier_size = 0;
}
void AnimationPlayer::_animation_process(double p_delta) {
if (playback.current.from) {
end_reached = false;
end_notify = false;
- _animation_process2(p_delta, playback.started);
+ bool started = playback.started; // The animation may be changed during process, so it is safer that the state is changed before process.
if (playback.started) {
playback.started = false;
}
+ cache_update_size = 0;
+ cache_update_prop_size = 0;
+ cache_update_bezier_size = 0;
+
+ AnimationData *prev_from = playback.current.from;
+ _animation_process2(p_delta, started);
+ if (prev_from != playback.current.from) {
+ return; // Animation has been changed in the process (may be caused by method track), abort process.
+ }
_animation_update_transforms();
+
if (end_reached) {
if (queued.size()) {
String old = playback.assigned;
@@ -2060,7 +2071,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) {
old_values->restore();
Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
- ur->create_action(TTR("Anim Apply Reset"));
+ ur->create_action(TTR("Animation Apply Reset"));
ur->add_do_method(new_values.ptr(), "restore");
ur->add_undo_method(old_values.ptr(), "restore");
ur->commit_action();
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index bd9b918900..fbc85bd5e1 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -1031,7 +1031,9 @@ void AnimationTree::_process_graph(double p_delta) {
}
NodePath path = a->track_get_path(i);
- ERR_CONTINUE(!track_cache.has(path));
+ if (!track_cache.has(path)) {
+ continue; // No path, but avoid error spamming.
+ }
TrackCache *track = track_cache[path];
ERR_CONTINUE(!state.track_map.has(path));
@@ -1582,8 +1584,8 @@ void AnimationTree::_process_graph(double p_delta) {
}
if (player2->is_playing() || seeked) {
- player2->play(anim_name);
player2->seek(at_anim_pos);
+ player2->play(anim_name);
t->playing = true;
playing_caches.insert(t);
} else {