Merge pull request #94858 from TokageItLab/early-break-loop-at-end

Determine `break_loop_at_end` 1 frame earlier using prediction by delta
This commit is contained in:
Rémi Verschelde 2024-07-28 17:47:09 +02:00
commit 7aba10b170
No known key found for this signature in database
GPG key ID: C3336907360768E1
4 changed files with 9 additions and 13 deletions

View file

@ -138,15 +138,11 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
bool p_seek = p_playback_info.seeked; bool p_seek = p_playback_info.seeked;
bool p_is_external_seeking = p_playback_info.is_external_seeking; bool p_is_external_seeking = p_playback_info.is_external_seeking;
bool is_just_looped = false;
// 1. Progress for AnimationNode. // 1. Progress for AnimationNode.
bool will_end = Animation::is_greater_or_equal_approx(cur_time + cur_delta, cur_len);
if (cur_loop_mode != Animation::LOOP_NONE) { if (cur_loop_mode != Animation::LOOP_NONE) {
if (cur_loop_mode == Animation::LOOP_LINEAR) { if (cur_loop_mode == Animation::LOOP_LINEAR) {
if (!Math::is_zero_approx(cur_len)) { if (!Math::is_zero_approx(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); cur_time = Math::fposmod(cur_time, cur_len);
} }
backward = false; backward = false;
@ -156,7 +152,6 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
backward = !backward; backward = !backward;
} else if (Animation::is_less_or_equal_approx(prev_time, cur_len) && Animation::is_greater_approx(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; backward = !backward;
is_just_looped = true; // Don't break with negative timescale since remain will not be 0.
} }
cur_time = Math::pingpong(cur_time, cur_len); cur_time = Math::pingpong(cur_time, cur_len);
} }
@ -190,7 +185,7 @@ AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixe
nti.position = cur_time; nti.position = cur_time;
nti.delta = cur_delta; nti.delta = cur_delta;
nti.loop_mode = cur_loop_mode; nti.loop_mode = cur_loop_mode;
nti.is_just_looped = is_just_looped; nti.will_end = will_end;
// 3. Progress for Animation. // 3. Progress for Animation.
double prev_playback_time = prev_time + start_offset; double prev_playback_time = prev_time + start_offset;

View file

@ -804,7 +804,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
pi.weight = 0; pi.weight = 0;
current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true);
// Don't process first node if not necessary, insteads process next node. // Don't process first node if not necessary, insteads process next node.
_transition_to_next_recursive(tree, p_state_machine, p_test_only); _transition_to_next_recursive(tree, p_state_machine, p_delta, p_test_only);
} }
// Check current node existence. // Check current node existence.
@ -881,7 +881,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
} }
// Find next and see when to transition. // Find next and see when to transition.
bool will_end = _transition_to_next_recursive(tree, p_state_machine, p_test_only) || current == AnimationNodeStateMachine::END_NODE; bool will_end = _transition_to_next_recursive(tree, p_state_machine, p_delta, p_test_only) || current == AnimationNodeStateMachine::END_NODE;
// Predict remaining time. // Predict remaining time.
if (will_end || ((p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) && !p_state_machine->has_transition_from(current))) { if (will_end || ((p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) && !p_state_machine->has_transition_from(current))) {
@ -899,10 +899,11 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
return current_nti; return current_nti;
} }
bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only) { bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, double p_delta, bool p_test_only) {
_reset_request_for_fading_from = false; _reset_request_for_fading_from = false;
AnimationMixer::PlaybackInfo pi; AnimationMixer::PlaybackInfo pi;
pi.delta = p_delta;
NextInfo next; NextInfo next;
Vector<StringName> transition_path; Vector<StringName> transition_path;
transition_path.push_back(current); transition_path.push_back(current);

View file

@ -306,7 +306,7 @@ class AnimationNodeStateMachinePlayback : public Resource {
AnimationNode::NodeTimeInfo _process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only); AnimationNode::NodeTimeInfo _process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only);
bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const; bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const;
bool _transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only); bool _transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, double p_delta, bool p_test_only);
NextInfo _find_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine) const; NextInfo _find_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine) const;
Ref<AnimationNodeStateMachineTransition> _check_group_transition(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const AnimationNodeStateMachine::Transition &p_transition, Ref<AnimationNodeStateMachine> &r_state_machine, bool &r_bypass) const; Ref<AnimationNodeStateMachineTransition> _check_group_transition(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const AnimationNodeStateMachine::Transition &p_transition, Ref<AnimationNodeStateMachine> &r_state_machine, bool &r_bypass) const;
bool _can_transition_to_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, NextInfo p_next, bool p_test_only); bool _can_transition_to_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, NextInfo p_next, bool p_test_only);

View file

@ -74,7 +74,7 @@ public:
// Needs internally to estimate remain time, the previous frame values are not retained. // Needs internally to estimate remain time, the previous frame values are not retained.
Animation::LoopMode loop_mode = Animation::LOOP_NONE; Animation::LoopMode loop_mode = Animation::LOOP_NONE;
bool is_just_looped = false; // For breaking loop, it is true when just looped. bool will_end = false; // For breaking loop, it is true when just looped.
bool is_infinity = false; // For unpredictable state machine's end. bool is_infinity = false; // For unpredictable state machine's end.
bool is_looping() { bool is_looping() {
@ -84,7 +84,7 @@ public:
if ((is_looping() && !p_break_loop) || is_infinity) { if ((is_looping() && !p_break_loop) || is_infinity) {
return HUGE_LENGTH; return HUGE_LENGTH;
} }
if (p_break_loop && is_just_looped) { if (is_looping() && p_break_loop && will_end) {
return 0; return 0;
} }
double remain = length - position; double remain = length - position;