Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add node started/finished signals for animation state machines #102398

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions doc/classes/AnimationNodeStateMachinePlayback.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,18 @@
<members>
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="true" />
</members>
<signals>
<signal name="node_finished">
<param index="0" name="node" type="StringName" />
<description>
Emitted when the [param node] finishes playback. If [param node] is a state machine set to grouped mode, its signals are passed through with its name prefixed.
</description>
</signal>
<signal name="node_started">
<param index="0" name="node" type="StringName" />
<description>
Emitted when the [param node] starts playback. If [param node] is a state machine set to grouped mode, its signals are passed through with its name prefixed.
</description>
</signal>
</signals>
</class>
46 changes: 42 additions & 4 deletions scene/animation/animation_node_state_machine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ void AnimationNodeStateMachinePlayback::_set_current(AnimationNodeStateMachine *
if (anodesm.is_null()) {
group_start_transition = Ref<AnimationNodeStateMachineTransition>();
group_end_transition = Ref<AnimationNodeStateMachineTransition>();
emit_signal(SceneStringName(node_started), current);
return;
}

Expand All @@ -223,8 +224,16 @@ void AnimationNodeStateMachinePlayback::_set_current(AnimationNodeStateMachine *
group_end_transition = Ref<AnimationNodeStateMachineTransition>();
}

// Validation.
// Validate grouped child state machine and ensure signals are connected for propagation.
if (anodesm->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) {
Ref<AnimationNodeStateMachinePlayback> playback = p_state_machine->get_animation_tree()->get(base_path + current + "/playback");
Callable callable = callable_mp(this, &AnimationNodeStateMachinePlayback::_propagate_grouped_child_signal);
if (!playback->is_connected(SceneStringName(node_started), callable)) {
String concatenated = vformat("%s/", current);
playback->connect(SceneStringName(node_started), callable.bind(concatenated, true));
playback->connect(SceneStringName(node_finished), callable.bind(concatenated, false));
}

indices = anodesm->find_transition_from(SceneStringName(Start));
int anodesm_start_size = indices.size();
indices = anodesm->find_transition_to(SceneStringName(End));
Expand All @@ -247,6 +256,8 @@ void AnimationNodeStateMachinePlayback::_set_current(AnimationNodeStateMachine *
if (anodesm_end_size != group_end_size) {
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 + ".");
}
} else {
emit_signal(SceneStringName(node_started), current);
}
}

Expand Down Expand Up @@ -346,12 +357,27 @@ float AnimationNodeStateMachinePlayback::get_fading_pos() const {
return fading_pos;
}

bool _is_grouped_state_machine(const Ref<AnimationNodeStateMachine> p_node) {
return p_node.is_valid() && p_node->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED;
}

void AnimationNodeStateMachinePlayback::_propagate_grouped_child_signal(const StringName p_child_current, String p_child_name, bool p_started) {
if (p_child_current == SceneStringName(Start) || p_child_current == SceneStringName(End)) {
return;
}
if (p_started) {
emit_signal(SceneStringName(node_started), p_child_name + p_child_current);
} else {
emit_signal(SceneStringName(node_finished), p_child_name + p_child_current);
}
}

void AnimationNodeStateMachinePlayback::_clear_path_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only) {
List<AnimationNode::ChildNode> child_nodes;
p_state_machine->get_child_nodes(&child_nodes);
for (const AnimationNode::ChildNode &child_node : child_nodes) {
Ref<AnimationNodeStateMachine> anodesm = child_node.node;
if (anodesm.is_valid() && anodesm->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) {
if (_is_grouped_state_machine(anodesm)) {
Ref<AnimationNodeStateMachinePlayback> playback = p_tree->get(base_path + child_node.name + "/playback");
ERR_FAIL_COND(playback.is_null());
playback->_set_base_path(base_path + child_node.name + "/");
Expand Down Expand Up @@ -789,7 +815,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St

if (teleport_request) {
teleport_request = false;
// Clear fadeing on teleport.
// Clear fading on teleport.
fading_from = StringName();
fadeing_from_nti = AnimationNode::NodeTimeInfo();
fading_pos = 0;
Expand Down Expand Up @@ -871,6 +897,9 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St

if (Animation::is_greater_or_equal_approx(fading_pos, fading_time)) {
// Finish fading.
if (!fading_from.is_empty() && !_is_grouped_state_machine(p_state_machine->get_node(fading_from))) {
emit_signal(SceneStringName(node_finished), fading_from);
}
fading_from = StringName();
fadeing_from_nti = AnimationNode::NodeTimeInfo();
}
Expand Down Expand Up @@ -932,6 +961,9 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT
pi.weight = 0;
p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only);
}
if (!current.is_empty() && !_is_grouped_state_machine(p_state_machine->get_node(current))) {
emit_signal(SceneStringName(node_finished), current);
}
fading_from = StringName();
fadeing_from_nti = AnimationNode::NodeTimeInfo();
fading_time = 0;
Expand Down Expand Up @@ -998,7 +1030,10 @@ bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p
playback = playback->duplicate();
}
playback->_next_main();
// Then, fadeing should be end.
// Then, fading should end.
if (!fading_from.is_empty() && !_is_grouped_state_machine(p_state_machine->get_node(fading_from))) {
emit_signal(SceneStringName(node_finished), fading_from);
}
fading_from = StringName();
fadeing_from_nti = AnimationNode::NodeTimeInfo();
fading_pos = 0;
Expand Down Expand Up @@ -1194,6 +1229,9 @@ void AnimationNodeStateMachinePlayback::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_current_length"), &AnimationNodeStateMachinePlayback::get_current_length);
ClassDB::bind_method(D_METHOD("get_fading_from_node"), &AnimationNodeStateMachinePlayback::get_fading_from_node);
ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachinePlayback::_get_travel_path);

ADD_SIGNAL(MethodInfo(SceneStringName(node_started), PropertyInfo(Variant::STRING_NAME, "node")));
ADD_SIGNAL(MethodInfo(SceneStringName(node_finished), PropertyInfo(Variant::STRING_NAME, "node")));
}

AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() {
Expand Down
1 change: 1 addition & 0 deletions scene/animation/animation_node_state_machine.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ class AnimationNodeStateMachinePlayback : public Resource {

bool is_grouped = false;

void _propagate_grouped_child_signal(const StringName p_child_current, String p_child_name, bool p_started);
void _travel_main(const StringName &p_state, bool p_reset_on_teleport = true);
void _start_main(const StringName &p_state, bool p_reset = true);
void _next_main();
Expand Down
2 changes: 2 additions & 0 deletions scene/scene_string_names.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ class SceneStringNames {

const StringName Start = StaticCString::create("Start");
const StringName End = StaticCString::create("End");
const StringName node_started = StaticCString::create("node_started");
const StringName node_finished = StaticCString::create("node_finished");

const StringName FlatButton = StaticCString::create("FlatButton");
};
Expand Down