1
0
Fork 0

Merge pull request #70278 from TokageItLab/add-animation-started-finished-signal-to-tree

Add `animation_started/finished` signals to `AnimationTree` and fix time accuracy in StateMachine
This commit is contained in:
Rémi Verschelde 2022-12-23 09:08:17 +01:00
commit ecd895a860
No known key found for this signature in database
GPG Key ID: C3336907360768E1
5 changed files with 39 additions and 8 deletions

View File

@ -111,11 +111,25 @@
</member> </member>
</members> </members>
<signals> <signals>
<signal name="animation_finished">
<param index="0" name="anim_name" type="StringName" />
<description>
Notifies when an animation finished playing.
[b]Note:[/b] This signal is not emitted if an animation is looping or aborted. Also be aware of the possibility of unseen playback by sync and xfade.
</description>
</signal>
<signal name="animation_player_changed"> <signal name="animation_player_changed">
<description> <description>
Emitted when the [member anim_player] is changed. Emitted when the [member anim_player] is changed.
</description> </description>
</signal> </signal>
<signal name="animation_started">
<param index="0" name="anim_name" type="StringName" />
<description>
Notifies when an animation starts playing.
[b]Note:[/b] This signal is not emitted if an animation is looping or playbacked from the middle. Also be aware of the possibility of unseen playback by sync and xfade.
</description>
</signal>
</signals> </signals>
<constants> <constants>
<constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessCallback"> <constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessCallback">

View File

@ -144,6 +144,19 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_ext
} }
} }
} }
// Emit start & finish signal. Internally, the detections are the same for backward.
// We should use call_deferred since the track keys are still being prosessed.
if (state->tree) {
// 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_time == 0) {
state->tree->call_deferred(SNAME("emit_signal"), "animation_started", animation);
}
// Finished.
if (prev_time < anim_size && cur_time >= anim_size) {
state->tree->call_deferred(SNAME("emit_signal"), "animation_finished", animation);
}
}
} }
if (play_mode == PLAY_MODE_FORWARD) { if (play_mode == PLAY_MODE_FORWARD) {

View File

@ -369,6 +369,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
// can't travel, then teleport // can't travel, then teleport
path.clear(); path.clear();
current = start_request; current = start_request;
play_start = true;
} }
start_request = StringName(); //clear start request start_request = StringName(); //clear start request
} }
@ -414,7 +415,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
fading_pos += p_time; fading_pos += p_time;
} }
fade_blend = MIN(1.0, fading_pos / fading_time); fade_blend = MIN(1.0, fading_pos / fading_time);
if (fade_blend >= 1.0) { if (fade_blend > 1.0) {
fading_from = StringName(); fading_from = StringName();
} }
} }
@ -423,9 +424,9 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
if (current_curve.is_valid()) { if (current_curve.is_valid()) {
fade_blend = current_curve->sample(fade_blend); fade_blend = current_curve->sample(fade_blend);
} }
float rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. double rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
float fade_blend_inv = 1.0 - fade_blend; double fade_blend_inv = 1.0 - fade_blend;
if (fading_from != StringName()) { if (fading_from != StringName()) {
p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend_inv) ? CMP_EPSILON : fade_blend_inv, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend_inv) ? CMP_EPSILON : fade_blend_inv, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
} }
@ -436,14 +437,14 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
} }
{ //advance and loop check { //advance and loop check
float next_pos = len_current - rem; double next_pos = len_current - rem;
end_loop = next_pos < pos_current; end_loop = next_pos < pos_current;
pos_current = next_pos; //looped pos_current = next_pos; //looped
} }
//find next //find next
StringName next; StringName next;
float next_xfade = 0.0; double next_xfade = 0.0;
AnimationNodeStateMachineTransition::SwitchMode switch_mode = AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE; AnimationNodeStateMachineTransition::SwitchMode switch_mode = AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE;
if (path.size()) { if (path.size()) {

View File

@ -114,8 +114,8 @@ class AnimationNodeStateMachinePlayback : public Resource {
StringName next; StringName next;
}; };
float len_current = 0.0; double len_current = 0.0;
float pos_current = 0.0; double pos_current = 0.0;
bool end_loop = false; bool end_loop = false;
StringName current; StringName current;

View File

@ -432,7 +432,6 @@ void AnimationNode::_bind_methods() {
GDVIRTUAL_BIND(_has_filter); GDVIRTUAL_BIND(_has_filter);
ADD_SIGNAL(MethodInfo("removed_from_graph")); ADD_SIGNAL(MethodInfo("removed_from_graph"));
ADD_SIGNAL(MethodInfo("tree_changed")); ADD_SIGNAL(MethodInfo("tree_changed"));
BIND_ENUM_CONSTANT(FILTER_IGNORE); BIND_ENUM_CONSTANT(FILTER_IGNORE);
@ -2037,6 +2036,10 @@ void AnimationTree::_bind_methods() {
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL); BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL);
ADD_SIGNAL(MethodInfo("animation_player_changed")); ADD_SIGNAL(MethodInfo("animation_player_changed"));
// Signals from AnimationNodes.
ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING_NAME, "anim_name")));
ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING_NAME, "anim_name")));
} }
AnimationTree::AnimationTree() { AnimationTree::AnimationTree() {