From 88e590c9d3dc011160e8f1d17b28150c36edb13f Mon Sep 17 00:00:00 2001 From: "Silc Lizard (Tokage) Renew" <61938263+TokageItLab@users.noreply.github.com> Date: Wed, 24 Jul 2024 01:00:42 +0900 Subject: [PATCH] Add approx comparing methods to Animation, use them on time comparison --- scene/animation/animation_blend_tree.cpp | 57 ++++++++++--------- scene/animation/animation_mixer.cpp | 42 +++++++------- .../animation_node_state_machine.cpp | 8 +-- scene/animation/animation_player.cpp | 38 ++++++------- scene/animation/animation_tree.h | 4 ++ scene/resources/animation.h | 16 ++++++ 6 files changed, 93 insertions(+), 72 deletions(-) diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 6e33a1b27ccc..59ebf3825354 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -144,7 +144,7 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe if (cur_loop_mode != Animation::LOOP_NONE) { if (cur_loop_mode == Animation::LOOP_LINEAR) { if (!Math::is_zero_approx(cur_len)) { - if (prev_time <= cur_len && cur_time > cur_len) { + if (Animation::is_less_or_equal_approx(prev_time, cur_len) && Animation::is_greater_approx(cur_time, cur_len)) { is_just_looped = true; // Don't break with negative timescale since remain will not be 0. } cur_time = Math::fposmod(cur_time, cur_len); @@ -152,9 +152,9 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe backward = false; } else { if (!Math::is_zero_approx(cur_len)) { - if (prev_time >= 0 && cur_time < 0) { + if (Animation::is_greater_or_equal_approx(prev_time, 0) && Animation::is_less_approx(cur_time, 0)) { backward = !backward; - } else if (prev_time <= cur_len && cur_time > cur_len) { + } else if (Animation::is_less_or_equal_approx(prev_time, cur_len) && Animation::is_greater_approx(cur_time, cur_len)) { backward = !backward; is_just_looped = true; // Don't break with negative timescale since remain will not be 0. } @@ -162,10 +162,10 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe } } } else { - if (cur_time < 0) { + if (Animation::is_less_approx(cur_time, 0)) { cur_delta += cur_time; cur_time = 0; - } else if (cur_time > cur_len) { + } else if (Animation::is_greater_approx(cur_time, cur_len)) { cur_delta += cur_time - cur_len; cur_time = cur_len; } @@ -173,11 +173,11 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe // If ended, don't progress AnimationNode. So set delta to 0. if (!Math::is_zero_approx(cur_delta)) { if (play_mode == PLAY_MODE_FORWARD) { - if (prev_time >= cur_len) { + if (Animation::is_greater_or_equal_approx(prev_time, cur_len)) { cur_delta = 0; } } else { - if (prev_time <= 0) { + if (Animation::is_less_or_equal_approx(prev_time, 0)) { cur_delta = 0; } } @@ -197,6 +197,7 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe double cur_playback_time = cur_time + start_offset; if (stretch_time_scale) { double mlt = anim_size / cur_len; + prev_playback_time *= mlt; cur_playback_time *= mlt; cur_delta *= mlt; } @@ -204,31 +205,31 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe if (!Math::is_zero_approx(anim_size)) { prev_playback_time = Math::fposmod(prev_playback_time, anim_size); cur_playback_time = Math::fposmod(cur_playback_time, anim_size); - if (prev_playback_time >= 0 && cur_playback_time < 0) { + if (Animation::is_greater_or_equal_approx(prev_playback_time, 0) && Animation::is_less_approx(cur_playback_time, 0)) { looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START; } - if (prev_playback_time <= anim_size && cur_playback_time > anim_size) { + if (Animation::is_less_or_equal_approx(prev_playback_time, anim_size) && Animation::is_greater_approx(cur_playback_time, anim_size)) { looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END; } } } else if (cur_loop_mode == Animation::LOOP_PINGPONG) { if (!Math::is_zero_approx(anim_size)) { - if (Math::fposmod(cur_playback_time, anim_size * 2.0) >= anim_size) { + if (Animation::is_greater_or_equal_approx(Math::fposmod(cur_playback_time, anim_size * 2.0), anim_size)) { cur_delta = -cur_delta; // Needed for retrieving discrete keys correctly. } prev_playback_time = Math::pingpong(prev_playback_time, anim_size); cur_playback_time = Math::pingpong(cur_playback_time, anim_size); - if (prev_playback_time >= 0 && cur_playback_time < 0) { + if (Animation::is_greater_or_equal_approx(prev_playback_time, 0) && Animation::is_less_approx(cur_playback_time, 0)) { looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START; } - if (prev_playback_time <= anim_size && cur_playback_time > anim_size) { + if (Animation::is_less_or_equal_approx(prev_playback_time, anim_size) && Animation::is_greater_approx(cur_playback_time, anim_size)) { looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END; } } } else { - if (cur_playback_time < 0) { + if (Animation::is_less_approx(cur_playback_time, 0)) { cur_playback_time = 0; - } else if (cur_playback_time > anim_size) { + } else if (Animation::is_greater_approx(cur_playback_time, anim_size)) { cur_playback_time = anim_size; } @@ -236,11 +237,11 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe // We should use call_deferred since the track keys are still being processed. if (process_state->tree && !p_test_only) { // AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection. - if (p_seek && !p_is_external_seeking && cur_playback_time == 0) { + if (p_seek && !p_is_external_seeking && Math::is_zero_approx(cur_playback_time)) { process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_started), animation); } // Finished. - if (prev_time + start_offset < anim_size && cur_playback_time >= anim_size) { + if (Animation::is_less_approx(prev_playback_time, anim_size) && Animation::is_greater_or_equal_approx(cur_playback_time, anim_size)) { process_state->tree->call_deferred(SNAME("emit_signal"), SceneStringName(animation_finished), animation); } } @@ -522,7 +523,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer: bool p_seek = p_playback_info.seeked; bool p_is_external_seeking = p_playback_info.is_external_seeking; - if (p_time == 0 && p_seek && !p_is_external_seeking) { + if (Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking) { clear_remaining_fade = true; // Reset occurs. } @@ -545,9 +546,9 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer: set_parameter(internal_active, false); set_parameter(time_to_restart, -1); } else if (!do_start && !cur_active) { - if (cur_time_to_restart >= 0.0 && !p_seek) { + if (Animation::is_greater_or_equal_approx(cur_time_to_restart, 0) && !p_seek) { cur_time_to_restart -= abs_delta; - if (cur_time_to_restart < 0) { + if (Animation::is_less_approx(cur_time_to_restart, 0)) { do_start = true; // Restart. } set_parameter(time_to_restart, cur_time_to_restart); @@ -590,8 +591,8 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer: real_t blend = 1.0; bool use_blend = sync; - if (cur_fade_in_remaining > 0) { - if (fade_in > 0) { + if (Animation::is_greater_approx(cur_fade_in_remaining, 0)) { + if (Animation::is_greater_approx(fade_in, 0)) { use_blend = true; blend = (fade_in - cur_fade_in_remaining) / fade_in; if (fade_in_curve.is_valid()) { @@ -604,7 +605,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer: if (is_fading_out) { use_blend = true; - if (fade_out > 0) { + if (Animation::is_greater_approx(fade_out, 0)) { blend = cur_fade_out_remaining / fade_out; if (fade_out_curve.is_valid()) { blend = 1.0 - fade_out_curve->sample(1.0 - blend); @@ -636,7 +637,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer: NodeTimeInfo os_nti = blend_input(1, pi, FILTER_PASS, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. - if (cur_fade_in_remaining <= 0 && !do_start && !is_fading_out && os_nti.get_remain(break_loop_at_end) <= fade_out) { + if (Animation::is_less_or_equal_approx(cur_fade_in_remaining, 0) && !do_start && !is_fading_out && Animation::is_less_or_equal_approx(os_nti.get_remain(break_loop_at_end), fade_out)) { is_fading_out = true; cur_fade_out_remaining = os_nti.get_remain(break_loop_at_end); cur_fade_in_remaining = 0; @@ -644,7 +645,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer: } if (!p_seek) { - if (os_nti.get_remain(break_loop_at_end) <= 0 || (is_fading_out && cur_fade_out_remaining <= 0)) { + if (Animation::is_less_or_equal_approx(os_nti.get_remain(break_loop_at_end), 0) || (is_fading_out && Animation::is_less_or_equal_approx(cur_fade_out_remaining, 0))) { set_parameter(internal_active, false); set_parameter(active, false); if (auto_restart) { @@ -1007,7 +1008,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer AnimationMixer::PlaybackInfo pi = p_playback_info; pi.weight = 1.0; - if (cur_seek_pos >= 0) { + if (Animation::is_greater_or_equal_approx(cur_seek_pos, 0)) { pi.time = cur_seek_pos; pi.seeked = true; pi.is_external_seeking = true; @@ -1252,7 +1253,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(const AnimationMix bool p_seek = p_playback_info.seeked; bool p_is_external_seeking = p_playback_info.is_external_seeking; - if (p_time == 0 && p_seek && !p_is_external_seeking) { + if (Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking) { clear_remaining_fade = true; // Reset occurs. } @@ -1317,7 +1318,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(const AnimationMix if (cur_prev_index < 0) { // Process current animation, check for transition. pi.weight = 1.0; cur_nti = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only); - if (input_data[cur_current_index].auto_advance && cur_nti.get_remain(input_data[cur_current_index].break_loop_at_end) <= xfade_time) { + if (input_data[cur_current_index].auto_advance && Animation::is_less_or_equal_approx(cur_nti.get_remain(input_data[cur_current_index].break_loop_at_end), xfade_time)) { set_parameter(transition_request, get_input_name((cur_current_index + 1) % get_input_count())); } } else { // Cross-fading from prev to current. @@ -1349,7 +1350,7 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(const AnimationMix pi.weight = blend; blend_input(cur_prev_index, pi, FILTER_IGNORE, true, p_test_only); if (!p_seek) { - if (cur_prev_xfading <= 0) { + if (Animation::is_less_or_equal_approx(cur_prev_xfading, 0)) { set_parameter(prev_index, -1); } cur_prev_xfading -= Math::abs(p_playback_info.delta); diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index e7626b3c2d9e..e57be69eaf9d 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -1049,7 +1049,7 @@ void AnimationMixer::blend_capture(double p_delta) { } capture_cache.remain -= p_delta * capture_cache.step; - if (capture_cache.remain <= 0.0) { + if (Animation::is_less_or_equal_approx(capture_cache.remain, 0)) { capture_cache.clear(); return; } @@ -1156,7 +1156,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (track->root_motion && calc_root) { double prev_time = time - delta; if (!backward) { - if (prev_time < 0) { + if (Animation::is_less_approx(prev_time, 0)) { switch (a->get_loop_mode()) { case Animation::LOOP_NONE: { prev_time = 0; @@ -1172,7 +1172,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { } } } else { - if (prev_time > a->get_length()) { + if (Animation::is_greater_approx(prev_time, (double)a->get_length())) { switch (a->get_loop_mode()) { case Animation::LOOP_NONE: { prev_time = (double)a->get_length(); @@ -1190,7 +1190,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { } Vector3 loc[2]; if (!backward) { - if (prev_time > time) { + if (Animation::is_greater_approx(prev_time, time)) { Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]); if (err != OK) { continue; @@ -1202,7 +1202,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { prev_time = 0; } } else { - if (prev_time < time) { + if (Animation::is_less_approx(prev_time, time)) { Error err = a->try_position_track_interpolate(i, prev_time, &loc[0]); if (err != OK) { continue; @@ -1244,7 +1244,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (track->root_motion && calc_root) { double prev_time = time - delta; if (!backward) { - if (prev_time < 0) { + if (Animation::is_less_approx(prev_time, 0)) { switch (a->get_loop_mode()) { case Animation::LOOP_NONE: { prev_time = 0; @@ -1260,7 +1260,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { } } } else { - if (prev_time > a->get_length()) { + if (Animation::is_greater_approx(prev_time, (double)a->get_length())) { switch (a->get_loop_mode()) { case Animation::LOOP_NONE: { prev_time = (double)a->get_length(); @@ -1278,7 +1278,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { } Quaternion rot[2]; if (!backward) { - if (prev_time > time) { + if (Animation::is_greater_approx(prev_time, time)) { Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]); if (err != OK) { continue; @@ -1290,7 +1290,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { prev_time = 0; } } else { - if (prev_time < time) { + if (Animation::is_less_approx(prev_time, time)) { Error err = a->try_rotation_track_interpolate(i, prev_time, &rot[0]); if (err != OK) { continue; @@ -1331,7 +1331,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { if (track->root_motion && calc_root) { double prev_time = time - delta; if (!backward) { - if (prev_time < 0) { + if (Animation::is_less_approx(prev_time, 0)) { switch (a->get_loop_mode()) { case Animation::LOOP_NONE: { prev_time = 0; @@ -1347,7 +1347,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { } } } else { - if (prev_time > a->get_length()) { + if (Animation::is_greater_approx(prev_time, (double)a->get_length())) { switch (a->get_loop_mode()) { case Animation::LOOP_NONE: { prev_time = (double)a->get_length(); @@ -1365,7 +1365,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { } Vector3 scale[2]; if (!backward) { - if (prev_time > time) { + if (Animation::is_greater_approx(prev_time, time)) { Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]); if (err != OK) { continue; @@ -1377,7 +1377,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { prev_time = 0; } } else { - if (prev_time < time) { + if (Animation::is_less_approx(prev_time, time)) { Error err = a->try_scale_track_interpolate(i, prev_time, &scale[0]); if (err != OK) { continue; @@ -1635,7 +1635,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { PlayingAudioStreamInfo pasi; pasi.index = t->audio_stream_playback->play_stream(stream, start_ofs, 0, 1.0, t->playback_type, t->bus); pasi.start = time; - if (len && end_ofs > 0) { // Force an end at a time. + if (len && Animation::is_greater_approx(end_ofs, 0)) { // Force an end at a time. pasi.len = len - start_ofs - end_ofs; } else { pasi.len = 0; @@ -1671,7 +1671,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { double at_anim_pos = 0.0; switch (anim->get_loop_mode()) { case Animation::LOOP_NONE: { - if (!is_external_seeking && ((!backward && time >= pos + (double)anim->get_length()) || (backward && time <= pos))) { + if (!is_external_seeking && ((!backward && Animation::is_greater_or_equal_approx(time, pos + (double)anim->get_length())) || (backward && Animation::is_less_or_equal_approx(time, pos)))) { continue; // Do nothing if current time is outside of length when started. } at_anim_pos = MIN((double)anim->get_length(), time - pos); // Seek to end. @@ -1841,23 +1841,23 @@ void AnimationMixer::_blend_apply() { } if (!track_info.loop) { if (!track_info.backward) { - if (track_info.time < pasi.start) { + if (Animation::is_less_approx(track_info.time, pasi.start)) { stop = true; } } else if (track_info.backward) { - if (track_info.time > pasi.start) { + if (Animation::is_greater_approx(track_info.time, pasi.start)) { stop = true; } } } - if (pasi.len > 0) { + if (Animation::is_greater_approx(pasi.len, 0)) { double len = 0.0; if (!track_info.backward) { - len = pasi.start > track_info.time ? (track_info.length - pasi.start) + track_info.time : track_info.time - pasi.start; + len = Animation::is_greater_approx(pasi.start, track_info.time) ? (track_info.length - pasi.start) + track_info.time : track_info.time - pasi.start; } else { - len = pasi.start < track_info.time ? (track_info.length - track_info.time) + pasi.start : pasi.start - track_info.time; + len = Animation::is_less_approx(pasi.start, track_info.time) ? (track_info.length - track_info.time) + pasi.start : pasi.start - track_info.time; } - if (len > pasi.len) { + if (Animation::is_greater_approx(len, pasi.len)) { stop = true; } } diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 8b497abd8c4f..ecf4054e23f7 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -702,7 +702,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St bool p_is_external_seeking = p_playback_info.is_external_seeking; // Check seek to 0 (means reset) by parent AnimationNode. - if (p_time == 0 && p_seek && !p_is_external_seeking) { + if (Math::is_zero_approx(p_time) && p_seek && !p_is_external_seeking) { if (p_state_machine->state_machine_type != AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED || is_end() || !playing) { // Restart state machine. if (p_state_machine->get_state_machine_type() != AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) { @@ -873,7 +873,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St } fadeing_from_nti = p_state_machine->blend_node(p_state_machine->states[fading_from].node, fading_from, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. - if (fading_pos >= fading_time) { + if (Animation::is_greater_or_equal_approx(fading_pos, fading_time)) { // Finish fading. fading_from = StringName(); fadeing_from_nti = AnimationNode::NodeTimeInfo(); @@ -887,7 +887,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St if (will_end || ((p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) && !p_state_machine->has_transition_from(current))) { // There is no next transition. if (fading_from != StringName()) { - return current_nti.get_remain() > fadeing_from_nti.get_remain() ? current_nti : fadeing_from_nti; + return Animation::is_greater_approx(current_nti.get_remain(), fadeing_from_nti.get_remain()) ? current_nti : fadeing_from_nti; } return current_nti; } @@ -1015,7 +1015,7 @@ bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p } if (current != AnimationNodeStateMachine::START_NODE && p_next.switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_AT_END) { - return current_nti.get_remain(p_next.break_loop_at_end) <= p_next.xfade; + return Animation::is_less_or_equal_approx(current_nti.get_remain(p_next.break_loop_at_end), p_next.xfade); } return true; } diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index bd8c7ff88217..19229f405a4e 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -164,35 +164,35 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f double delta = p_started ? 0 : p_delta * speed; double next_pos = cd.pos + delta; - real_t len = cd.from->animation->get_length(); + double len = cd.from->animation->get_length(); Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE; switch (cd.from->animation->get_loop_mode()) { case Animation::LOOP_NONE: { - if (next_pos < 0) { + if (Animation::is_less_approx(next_pos, 0)) { next_pos = 0; - } else if (next_pos > len) { + } else if (Animation::is_greater_approx(next_pos, len)) { next_pos = len; } delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here). } break; case Animation::LOOP_LINEAR: { - if (next_pos < 0 && cd.pos >= 0) { + if (Animation::is_less_approx(next_pos, 0) && Animation::is_greater_or_equal_approx(cd.pos, 0)) { looped_flag = Animation::LOOPED_FLAG_START; } - if (next_pos > len && cd.pos <= len) { + if (Animation::is_greater_approx(next_pos, len) && Animation::is_less_or_equal_approx(cd.pos, len)) { looped_flag = Animation::LOOPED_FLAG_END; } next_pos = Math::fposmod(next_pos, (double)len); } break; case Animation::LOOP_PINGPONG: { - if (next_pos < 0 && cd.pos >= 0) { + if (Animation::is_less_approx(next_pos, 0) && Animation::is_greater_or_equal_approx(cd.pos, 0)) { cd.speed_scale *= -1.0; looped_flag = Animation::LOOPED_FLAG_START; } - if (next_pos > len && cd.pos <= len) { + if (Animation::is_greater_approx(next_pos, len) && Animation::is_less_or_equal_approx(cd.pos, len)) { cd.speed_scale *= -1.0; looped_flag = Animation::LOOPED_FLAG_END; } @@ -209,16 +209,16 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f // End detection. if (p_is_current) { if (cd.from->animation->get_loop_mode() == Animation::LOOP_NONE) { - if (!backwards && prev_pos <= len && next_pos == len) { + if (!backwards && Animation::is_less_or_equal_approx(prev_pos, len) && Math::is_equal_approx(next_pos, len)) { // Playback finished. end_reached = true; - end_notify = prev_pos < len; // Notify only if not already at the end. + end_notify = Animation::is_less_approx(prev_pos, len); // Notify only if not already at the end. p_blend = 1.0; } - if (backwards && prev_pos >= 0 && next_pos == 0) { + if (backwards && Animation::is_greater_or_equal_approx(prev_pos, 0) && Math::is_equal_approx(next_pos, 0)) { // Playback finished. end_reached = true; - end_notify = prev_pos > 0; // Notify only if not already at the beginning. + end_notify = Animation::is_greater_approx(prev_pos, 0); // Notify only if not already at the beginning. p_blend = 1.0; } } @@ -277,7 +277,7 @@ void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) { for (List::Element *E = c.blend.front(); E; E = E->next()) { Blend &b = E->get(); b.blend_left = MAX(0, b.blend_left - Math::absf(speed_scale * p_delta) / b.blend_time); - if (b.blend_left <= 0) { + if (Animation::is_less_or_equal_approx(b.blend_left, 0)) { to_erase.push_back(E); b.blend_left = CMP_EPSILON; // May want to play last frame. } @@ -401,7 +401,7 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo bk.from = c.current.from->name; bk.to = name; - if (p_custom_blend >= 0) { + if (Animation::is_greater_or_equal_approx(p_custom_blend, 0)) { blend_time = p_custom_blend; } else if (blend_times.has(bk)) { blend_time = blend_times[bk]; @@ -419,10 +419,10 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo } } - if (p_custom_blend < 0 && blend_time == 0 && default_blend_time) { + if (Animation::is_less_approx(p_custom_blend, 0) && Math::is_zero_approx(blend_time) && default_blend_time) { blend_time = default_blend_time; } - if (blend_time > 0) { + if (Animation::is_greater_approx(blend_time, 0)) { Blend b; b.data = c.current; b.blend_left = get_current_blend_amount(); @@ -449,10 +449,10 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo c.assigned = name; emit_signal(SNAME("current_animation_changed"), c.assigned); } else { - if (p_from_end && c.current.pos == 0) { + if (p_from_end && Math::is_zero_approx(c.current.pos)) { // Animation reset but played backwards, set position to the end. seek_internal(c.current.from->animation->get_length(), true, true, true); - } else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) { + } else if (!p_from_end && Math::is_equal_approx(c.current.pos, (double)c.current.from->animation->get_length())) { // Animation resumed but already ended, set position to the beginning. seek_internal(0, true, true, true); } else if (playing) { @@ -585,7 +585,7 @@ void AnimationPlayer::seek_internal(double p_time, bool p_update, bool p_update_ return; } - bool is_backward = p_time < playback.current.pos; + bool is_backward = Animation::is_less_approx(p_time, playback.current.pos); _check_immediately_after_start(); @@ -708,7 +708,7 @@ void AnimationPlayer::set_blend_time(const StringName &p_animation1, const Strin BlendKey bk; bk.from = p_animation1; bk.to = p_animation2; - if (p_time == 0) { + if (Math::is_zero_approx(p_time)) { blend_times.erase(bk); } else { blend_times[bk] = p_time; diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 62a01b758f61..6698427233ef 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -87,6 +87,10 @@ class AnimationNode : public Resource { if (p_break_loop && is_just_looped) { return 0; } + double remain = length - position; + if (Math::is_zero_approx(remain)) { + return 0; + } return length - position; } }; diff --git a/scene/resources/animation.h b/scene/resources/animation.h index cb12b12c0e9f..d5daaac58a5e 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -527,6 +527,22 @@ class Animation : public Resource { static Variant interpolate_variant(const Variant &a, const Variant &b, float c, bool p_snap_array_element = false); static Variant cubic_interpolate_in_time_variant(const Variant &pre_a, const Variant &a, const Variant &b, const Variant &post_b, float c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t, bool p_snap_array_element = false); + static bool is_less_or_equal_approx(double a, double b) { + return a < b || Math::is_equal_approx(a, b); + } + + static bool is_less_approx(double a, double b) { + return a < b && !Math::is_equal_approx(a, b); + } + + static bool is_greater_or_equal_approx(double a, double b) { + return a > b || Math::is_equal_approx(a, b); + } + + static bool is_greater_approx(double a, double b) { + return a > b && !Math::is_equal_approx(a, b); + } + static TrackType get_cache_type(TrackType p_type); Animation();