Ver código fonte

Add animation_started/finished signals to AnimationTree

Silc Renew 2 anos atrás
pai
commit
4cd144d5fb

+ 14 - 0
doc/classes/AnimationTree.xml

@@ -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">

+ 13 - 0
scene/animation/animation_blend_tree.cpp

@@ -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) {

+ 6 - 5
scene/animation/animation_node_state_machine.cpp

@@ -379,6 +379,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
 			}
@@ -424,7 +425,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();
 			}
 		}
@@ -433,9 +434,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.
 	}
@@ -446,14 +447,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()) {

+ 2 - 2
scene/animation/animation_node_state_machine.h

@@ -111,8 +111,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;

+ 4 - 1
scene/animation/animation_tree.cpp

@@ -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() {