From 7a7f5a22162acf84bfd11f3b088a39103f068d18 Mon Sep 17 00:00:00 2001 From: jitspoe Date: Tue, 12 Nov 2019 22:16:13 -0500 Subject: [PATCH] Fix animation blending bug where an animation with a short blend time played immediately after an animation with a long blend time would play with a long blend time or cause popping/incorrect animation positions. --- scene/animation/animation_player.cpp | 29 +++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index cc6fadd9b20a..b76e49b86ff9 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -1072,25 +1072,34 @@ void AnimationPlayer::_animation_process2(double p_delta, bool p_started) { accum_pass++; 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); + float blend = 1.0; // First animation we play at 100% blend - List::Element *prev = nullptr; - for (List::Element *E = c.blend.back(); E; E = prev) { + List::Element *next = NULL; + for (List::Element *E = c.blend.front(); E; E = next) { Blend &b = E->get(); - float blend = b.blend_left / b.blend_time; + // Note: There may be issues if an animation event triggers an animation change while this blend is active, + // so it is best to use "deferred" calls instead of "immediate" for animation events that can trigger new animations. + _animation_process_data(b.data, p_delta, blend, false, false); + blend = 1.0 - b.blend_left / b.blend_time; // This is how much to blend the NEXT animation b.blend_left -= Math::absf(speed_scale * p_delta); - prev = E->prev(); + next = E->next(); if (b.blend_left < 0) { - c.blend.erase(E); + // If the blend of this has finished, we need to remove ALL the previous blends + List::Element *prev; + while (E) { + prev = E->prev(); + c.blend.erase(E); + E = prev; + } } - // 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); } + + _animation_process_data(c.current, p_delta, blend, seeked, p_started); } void AnimationPlayer::_animation_update_transforms() { @@ -1643,6 +1652,8 @@ void AnimationPlayer::play(const StringName &p_name, double p_custom_blend, floa b.data = c.current; b.blend_time = b.blend_left = blend_time; c.blend.push_back(b); + } else { + c.blend.clear(); } }