diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml
index 5298727b0f77..fb755813e660 100644
--- a/doc/classes/AnimationNode.xml
+++ b/doc/classes/AnimationNode.xml
@@ -244,5 +244,11 @@
Paths matching the filter will be blended (by the blend value).
+
+ The node has started playback.
+
+
+ The node has finished playback.
+
diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml
index 4a63b35ba051..af25395a0ba0 100644
--- a/doc/classes/AnimationTree.xml
+++ b/doc/classes/AnimationTree.xml
@@ -45,6 +45,13 @@
Emitted when the [member anim_player] is changed.
+
+
+
+
+ Emitted when the [param node] state changes during processing or playback.
+
+
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 019a14e556c6..a2b4b03abce2 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -696,6 +696,10 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer:
set_parameter(fade_in_remaining, cur_fade_in_remaining);
set_parameter(fade_out_remaining, cur_fade_out_remaining);
+ if (cur_active != (bool)get_parameter(active)) {
+ _notify_tree(cur_active ? NOTIFY_FINISHED : NOTIFY_STARTED);
+ }
+
return cur_internal_active ? os_nti : main_nti;
}
@@ -1451,6 +1455,7 @@ AnimationNodeOutput::AnimationNodeOutput() {
void AnimationNodeBlendTree::add_node(const StringName &p_name, Ref p_node, const Vector2 &p_position) {
ERR_FAIL_COND(nodes.has(p_name));
ERR_FAIL_COND(p_node.is_null());
+ ERR_FAIL_COND(node_to_name.has(*p_node));
ERR_FAIL_COND(p_name == SceneStringName(output));
ERR_FAIL_COND(String(p_name).contains_char('/'));
@@ -1459,6 +1464,7 @@ void AnimationNodeBlendTree::add_node(const StringName &p_name, Refget_input_count());
nodes[p_name] = n;
+ node_to_name[*p_node] = p_name;
emit_changed();
emit_signal(SNAME("tree_changed"));
@@ -1476,12 +1482,10 @@ Ref AnimationNodeBlendTree::get_node(const StringName &p_name) co
}
StringName AnimationNodeBlendTree::get_node_name(const Ref &p_node) const {
- for (const KeyValue &E : nodes) {
- if (E.value.node == p_node) {
- return E.key;
- }
+ AHashMap::ConstIterator E = node_to_name.find(*p_node);
+ if (E) {
+ return E->value;
}
-
ERR_FAIL_V(StringName());
}
@@ -1525,6 +1529,7 @@ void AnimationNodeBlendTree::remove_node(const StringName &p_name) {
{
Ref node = nodes[p_name].node;
+ node_to_name.erase(*node);
node->disconnect(SNAME("tree_changed"), callable_mp(this, &AnimationNodeBlendTree::_tree_changed));
node->disconnect(SNAME("animation_node_renamed"), callable_mp(this, &AnimationNodeBlendTree::_animation_node_renamed));
node->disconnect(SNAME("animation_node_removed"), callable_mp(this, &AnimationNodeBlendTree::_animation_node_removed));
@@ -1554,8 +1559,8 @@ void AnimationNodeBlendTree::rename_node(const StringName &p_name, const StringN
ERR_FAIL_COND(p_new_name == SceneStringName(output));
nodes[p_name].node->disconnect_changed(callable_mp(this, &AnimationNodeBlendTree::_node_changed));
-
nodes[p_new_name] = nodes[p_name];
+ node_to_name[*(nodes[p_new_name].node)] = p_new_name;
nodes.erase(p_name);
// Rename connections.
@@ -1853,7 +1858,8 @@ void AnimationNodeBlendTree::_initialize_node_tree() {
n.node = output;
n.position = Vector2(300, 150);
n.connections.resize(1);
- nodes["output"] = n;
+ nodes[SceneStringName(output)] = n;
+ node_to_name[*n.node] = SceneStringName(output);
}
AnimationNodeBlendTree::AnimationNodeBlendTree() {
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index 1b3d7f236e39..ec95aef91070 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -411,6 +411,7 @@ class AnimationNodeBlendTree : public AnimationRootNode {
};
AHashMap nodes;
+ AHashMap node_to_name;
Vector2 graph_offset;
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 19acf8c1b161..0c7ba4c78714 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -194,6 +194,7 @@ AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() {
void AnimationNodeStateMachinePlayback::_set_current(AnimationNodeStateMachine *p_state_machine, const StringName &p_state) {
current = p_state;
+
if (current == StringName()) {
group_start_transition = Ref();
group_end_transition = Ref();
@@ -490,6 +491,7 @@ void AnimationNodeStateMachinePlayback::_start(AnimationNodeStateMachine *p_stat
teleport_request = true;
stop_request = false;
start_request = StringName();
+ p_state_machine->_notify_tree(AnimationNode::NOTIFY_STARTED);
}
bool AnimationNodeStateMachinePlayback::_travel(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_is_allow_transition_to_self, bool p_test_only) {
@@ -719,6 +721,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
travel_request = StringName();
path.clear();
playing = false;
+ p_state_machine->_notify_tree(AnimationNode::NOTIFY_FINISHED);
return AnimationNode::NodeTimeInfo();
}
@@ -883,8 +886,14 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
if (will_end || ((p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) && !p_state_machine->has_transition_from(current))) {
// There is no next transition.
if (fading_from != StringName()) {
+ if (MAX(current_nti.get_remain(), fadeing_from_nti.get_remain()) <= 0) {
+ p_state_machine->_notify_tree(AnimationNode::NOTIFY_FINISHED);
+ }
return Animation::is_greater_approx(current_nti.get_remain(), fadeing_from_nti.get_remain()) ? current_nti : fadeing_from_nti;
}
+ if (current_nti.get_remain() <= 0) {
+ p_state_machine->_notify_tree(AnimationNode::NOTIFY_FINISHED);
+ }
return current_nti;
}
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index f1c01b1e8075..712a940ae16e 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -587,6 +587,19 @@ void AnimationNode::_bind_methods() {
BIND_ENUM_CONSTANT(FILTER_PASS);
BIND_ENUM_CONSTANT(FILTER_STOP);
BIND_ENUM_CONSTANT(FILTER_BLEND);
+
+ BIND_ENUM_CONSTANT(NOTIFY_STARTED);
+ BIND_ENUM_CONSTANT(NOTIFY_FINISHED);
+}
+
+void AnimationNode::_notify_tree(AnimationNode::NotifyReason p_reason) {
+ AnimationNodeBlendTree *blend_tree = Object::cast_to(node_state.parent);
+ if (blend_tree) {
+ StringName node_name = blend_tree->get_node_name(this);
+ if (!node_name.is_empty()) {
+ process_state->tree->emit_signal(SceneStringName(node_notify), node_name, p_reason);
+ }
+ }
}
AnimationNode::AnimationNode() {
@@ -991,6 +1004,7 @@ void AnimationTree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player");
ADD_SIGNAL(MethodInfo(SNAME("animation_player_changed")));
+ ADD_SIGNAL(MethodInfo(SceneStringName(node_notify), PropertyInfo(Variant::STRING_NAME, "node"), PropertyInfo(Variant::INT, "reason")));
}
AnimationTree::AnimationTree() {
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index d5b1d4ea460b..7200ddcd7376 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -54,6 +54,11 @@ class AnimationNode : public Resource {
FILTER_BLEND
};
+ enum NotifyReason {
+ NOTIFY_STARTED,
+ NOTIFY_FINISHED
+ };
+
struct Input {
String name;
};
@@ -181,6 +186,8 @@ class AnimationNode : public Resource {
void _validate_property(PropertyInfo &p_property) const;
+ void _notify_tree(AnimationNode::NotifyReason p_reason);
+
GDVIRTUAL0RC(Dictionary, _get_child_nodes)
GDVIRTUAL0RC(Array, _get_parameter_list)
GDVIRTUAL1RC(Ref, _get_child_by_name, StringName)
@@ -243,6 +250,7 @@ class AnimationNode : public Resource {
};
VARIANT_ENUM_CAST(AnimationNode::FilterAction)
+VARIANT_ENUM_CAST(AnimationNode::NotifyReason)
// Root node does not allow inputs.
class AnimationRootNode : public AnimationNode {
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 068487e45786..5475f982f785 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -85,6 +85,7 @@ class SceneStringNames {
const StringName sort_children = StaticCString::create("sort_children");
const StringName finished = StaticCString::create("finished");
+ const StringName node_notify = StaticCString::create("node_notify");
const StringName animation_finished = StaticCString::create("animation_finished");
const StringName animation_changed = StaticCString::create("animation_changed");
const StringName animation_started = StaticCString::create("animation_started");