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:
commit
ecd895a860
|
@ -111,11 +111,25 @@
|
|||
</member>
|
||||
</members>
|
||||
<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">
|
||||
<description>
|
||||
Emitted when the [member anim_player] is changed.
|
||||
</description>
|
||||
</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>
|
||||
<constants>
|
||||
<constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessCallback">
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -369,6 +369,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
|
|||
// can't travel, then teleport
|
||||
path.clear();
|
||||
current = start_request;
|
||||
play_start = true;
|
||||
}
|
||||
start_request = StringName(); //clear start request
|
||||
}
|
||||
|
@ -414,7 +415,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
|
|||
fading_pos += p_time;
|
||||
}
|
||||
fade_blend = MIN(1.0, fading_pos / fading_time);
|
||||
if (fade_blend >= 1.0) {
|
||||
if (fade_blend > 1.0) {
|
||||
fading_from = StringName();
|
||||
}
|
||||
}
|
||||
|
@ -423,9 +424,9 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
|
|||
if (current_curve.is_valid()) {
|
||||
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()) {
|
||||
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
|
||||
float next_pos = len_current - rem;
|
||||
double next_pos = len_current - rem;
|
||||
end_loop = next_pos < pos_current;
|
||||
pos_current = next_pos; //looped
|
||||
}
|
||||
|
||||
//find next
|
||||
StringName next;
|
||||
float next_xfade = 0.0;
|
||||
double next_xfade = 0.0;
|
||||
AnimationNodeStateMachineTransition::SwitchMode switch_mode = AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE;
|
||||
|
||||
if (path.size()) {
|
||||
|
|
|
@ -114,8 +114,8 @@ class AnimationNodeStateMachinePlayback : public Resource {
|
|||
StringName next;
|
||||
};
|
||||
|
||||
float len_current = 0.0;
|
||||
float pos_current = 0.0;
|
||||
double len_current = 0.0;
|
||||
double pos_current = 0.0;
|
||||
bool end_loop = false;
|
||||
|
||||
StringName current;
|
||||
|
|
|
@ -432,7 +432,6 @@ void AnimationNode::_bind_methods() {
|
|||
GDVIRTUAL_BIND(_has_filter);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("removed_from_graph"));
|
||||
|
||||
ADD_SIGNAL(MethodInfo("tree_changed"));
|
||||
|
||||
BIND_ENUM_CONSTANT(FILTER_IGNORE);
|
||||
|
@ -2037,6 +2036,10 @@ void AnimationTree::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL);
|
||||
|
||||
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() {
|
||||
|
|
Loading…
Reference in New Issue