Skip to content

Commit 5fe8eeb

Browse files
committed
Merge pull request #102398 from a-johnston/animation_state_machine_signals
Add node started/finished signals for animation state machines
2 parents 912be41 + d720061 commit 5fe8eeb

File tree

4 files changed

+62
-17
lines changed

4 files changed

+62
-17
lines changed

doc/classes/AnimationNodeStateMachinePlayback.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,19 @@
9393
<members>
9494
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="true" />
9595
</members>
96+
<signals>
97+
<signal name="state_finished">
98+
<param index="0" name="state" type="StringName" />
99+
<description>
100+
Emitted when the [param state] finishes playback. If [param state] is a state machine set to grouped mode, its signals are passed through with its name prefixed.
101+
If there is a crossfade, this will be fired when the influence of the [method get_fading_from_node] animation is no longer present.
102+
</description>
103+
</signal>
104+
<signal name="state_started">
105+
<param index="0" name="state" type="StringName" />
106+
<description>
107+
Emitted when the [param state] starts playback. If [param state] is a state machine set to grouped mode, its signals are passed through with its name prefixed.
108+
</description>
109+
</signal>
110+
</signals>
96111
</class>

scene/animation/animation_node_state_machine.cpp

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,12 @@ void AnimationNodeStateMachinePlayback::_set_current(AnimationNodeStateMachine *
200200
return;
201201
}
202202

203+
AnimationTree *tree = p_state_machine->process_state ? p_state_machine->process_state->tree : nullptr;
203204
Ref<AnimationNodeStateMachine> anodesm = p_state_machine->find_node_by_path(current);
204205
if (anodesm.is_null()) {
205206
group_start_transition = Ref<AnimationNodeStateMachineTransition>();
206207
group_end_transition = Ref<AnimationNodeStateMachineTransition>();
208+
_signal_state_change(tree, current, true);
207209
return;
208210
}
209211

@@ -247,6 +249,8 @@ void AnimationNodeStateMachinePlayback::_set_current(AnimationNodeStateMachine *
247249
if (anodesm_end_size != group_end_size) {
248250
ERR_PRINT_ED("There is a mismatch in the number of end transitions in and out of the Grouped AnimationNodeStateMachine on AnimationNodeStateMachine: " + base_path + current + ".");
249251
}
252+
} else {
253+
_signal_state_change(tree, current, true);
250254
}
251255
}
252256

@@ -346,12 +350,35 @@ float AnimationNodeStateMachinePlayback::get_fading_pos() const {
346350
return fading_pos;
347351
}
348352

353+
bool _is_grouped_state_machine(const Ref<AnimationNodeStateMachine> p_node) {
354+
return p_node.is_valid() && p_node->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED;
355+
}
356+
357+
void AnimationNodeStateMachinePlayback::_clear_fading(AnimationNodeStateMachine *p_state_machine, const StringName &p_state) {
358+
if (!p_state.is_empty() && !_is_grouped_state_machine(p_state_machine->get_node(p_state))) {
359+
_signal_state_change(p_state_machine->get_animation_tree(), p_state, false);
360+
}
361+
fading_from = StringName();
362+
fadeing_from_nti = AnimationNode::NodeTimeInfo();
363+
}
364+
365+
void AnimationNodeStateMachinePlayback::_signal_state_change(AnimationTree *p_animation_tree, const StringName &p_state, bool p_started) {
366+
if (is_grouped && p_animation_tree && p_state != SceneStringName(Start) && p_state != SceneStringName(End)) {
367+
AnimationNodeStateMachinePlayback *parent_playback = *_get_parent_playback(p_animation_tree);
368+
if (parent_playback) {
369+
String prefix = base_path.substr(base_path.rfind_char('/', base_path.length() - 2) + 1);
370+
parent_playback->_signal_state_change(p_animation_tree, prefix + p_state, p_started);
371+
}
372+
}
373+
emit_signal(p_started ? SceneStringName(state_started) : SceneStringName(state_finished), p_state);
374+
}
375+
349376
void AnimationNodeStateMachinePlayback::_clear_path_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only) {
350377
List<AnimationNode::ChildNode> child_nodes;
351378
p_state_machine->get_child_nodes(&child_nodes);
352379
for (const AnimationNode::ChildNode &child_node : child_nodes) {
353380
Ref<AnimationNodeStateMachine> anodesm = child_node.node;
354-
if (anodesm.is_valid() && anodesm->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) {
381+
if (_is_grouped_state_machine(anodesm)) {
355382
Ref<AnimationNodeStateMachinePlayback> playback = p_tree->get(base_path + child_node.name + "/playback");
356383
ERR_FAIL_COND(playback.is_null());
357384
playback->_set_base_path(base_path + child_node.name + "/");
@@ -678,18 +705,16 @@ bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree,
678705
}
679706
}
680707

681-
AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
682-
AnimationNode::NodeTimeInfo nti = _process(p_base_path, p_state_machine, p_playback_info, p_test_only);
708+
AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
709+
AnimationNode::NodeTimeInfo nti = _process(p_state_machine, p_playback_info, p_test_only);
683710
start_request = StringName();
684711
next_request = false;
685712
stop_request = false;
686713
reset_request_on_teleport = false;
687714
return nti;
688715
}
689716

690-
AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
691-
_set_base_path(p_base_path);
692-
717+
AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
693718
AnimationTree *tree = p_state_machine->process_state->tree;
694719

695720
double p_time = p_playback_info.time;
@@ -789,7 +814,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
789814

790815
if (teleport_request) {
791816
teleport_request = false;
792-
// Clear fadeing on teleport.
817+
// Clear fading on teleport.
793818
fading_from = StringName();
794819
fadeing_from_nti = AnimationNode::NodeTimeInfo();
795820
fading_pos = 0;
@@ -871,8 +896,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
871896

872897
if (Animation::is_greater_or_equal_approx(fading_pos, fading_time)) {
873898
// Finish fading.
874-
fading_from = StringName();
875-
fadeing_from_nti = AnimationNode::NodeTimeInfo();
899+
_clear_fading(p_state_machine, fading_from);
876900
}
877901
}
878902

@@ -932,8 +956,7 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT
932956
pi.weight = 0;
933957
p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only);
934958
}
935-
fading_from = StringName();
936-
fadeing_from_nti = AnimationNode::NodeTimeInfo();
959+
_clear_fading(p_state_machine, current);
937960
fading_time = 0;
938961
fading_pos = 0;
939962
}
@@ -998,9 +1021,8 @@ bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p
9981021
playback = playback->duplicate();
9991022
}
10001023
playback->_next_main();
1001-
// Then, fadeing should be end.
1002-
fading_from = StringName();
1003-
fadeing_from_nti = AnimationNode::NodeTimeInfo();
1024+
// Then, fading should end.
1025+
_clear_fading(p_state_machine, fading_from);
10041026
fading_pos = 0;
10051027
} else {
10061028
return true;
@@ -1194,6 +1216,9 @@ void AnimationNodeStateMachinePlayback::_bind_methods() {
11941216
ClassDB::bind_method(D_METHOD("get_current_length"), &AnimationNodeStateMachinePlayback::get_current_length);
11951217
ClassDB::bind_method(D_METHOD("get_fading_from_node"), &AnimationNodeStateMachinePlayback::get_fading_from_node);
11961218
ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachinePlayback::_get_travel_path);
1219+
1220+
ADD_SIGNAL(MethodInfo(SceneStringName(state_started), PropertyInfo(Variant::STRING_NAME, "state")));
1221+
ADD_SIGNAL(MethodInfo(SceneStringName(state_finished), PropertyInfo(Variant::STRING_NAME, "state")));
11971222
}
11981223

11991224
AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() {
@@ -1611,12 +1636,13 @@ Vector2 AnimationNodeStateMachine::get_graph_offset() const {
16111636
AnimationNode::NodeTimeInfo AnimationNodeStateMachine::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) {
16121637
Ref<AnimationNodeStateMachinePlayback> playback_new = get_parameter(playback);
16131638
ERR_FAIL_COND_V(playback_new.is_null(), AnimationNode::NodeTimeInfo());
1639+
playback_new->_set_base_path(node_state.get_base_path());
16141640
playback_new->_set_grouped(state_machine_type == STATE_MACHINE_TYPE_GROUPED);
16151641
if (p_test_only) {
16161642
playback_new = playback_new->duplicate(); // Don't process original when testing.
16171643
}
16181644

1619-
return playback_new->process(node_state.get_base_path(), this, p_playback_info, p_test_only);
1645+
return playback_new->process(this, p_playback_info, p_test_only);
16201646
}
16211647

16221648
String AnimationNodeStateMachine::get_caption() const {

scene/animation/animation_node_state_machine.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,8 @@ class AnimationNodeStateMachinePlayback : public Resource {
288288

289289
bool is_grouped = false;
290290

291+
void _clear_fading(AnimationNodeStateMachine *p_state_machine, const StringName &p_state);
292+
void _signal_state_change(AnimationTree *p_animation_tree, const StringName &p_state, bool p_started);
291293
void _travel_main(const StringName &p_state, bool p_reset_on_teleport = true);
292294
void _start_main(const StringName &p_state, bool p_reset = true);
293295
void _next_main();
@@ -302,8 +304,8 @@ class AnimationNodeStateMachinePlayback : public Resource {
302304
bool _travel_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const String &p_path, bool p_is_allow_transition_to_self, bool p_is_parent_same_state, bool p_test_only);
303305
void _start_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const String &p_path, bool p_test_only);
304306

305-
AnimationNode::NodeTimeInfo process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only);
306-
AnimationNode::NodeTimeInfo _process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only);
307+
AnimationNode::NodeTimeInfo process(AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only);
308+
AnimationNode::NodeTimeInfo _process(AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only);
307309

308310
bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const;
309311
bool _transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, double p_delta, bool p_test_only);

scene/scene_string_names.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ class SceneStringNames {
153153

154154
const StringName Start = "Start";
155155
const StringName End = "End";
156+
const StringName state_started = "state_started";
157+
const StringName state_finished = "state_finished";
156158

157159
const StringName FlatButton = "FlatButton";
158160
};

0 commit comments

Comments
 (0)