Skip to content
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
12 changes: 12 additions & 0 deletions doc/classes/AnimationNodeBlendSpace1D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@
A resource used by [AnimationNodeBlendTree].
[AnimationNodeBlendSpace1D] represents a virtual axis on which any type of [AnimationRootNode]s can be added using [method add_blend_point]. Outputs the linear blend of the two [AnimationRootNode]s adjacent to the current value.
You can set the extents of the axis with [member min_space] and [member max_space].

Optionally, signals can be used by setting an [AnimationNodeObserverBlendSpace] through [AnimationTree].
[codeblocks]
[gdscript]
var observer = tree.get("parameters/BlendSpace/observer")
observer.closest_point_changed.connect(on_closest_point_changed)
[/gdscript]
[csharp]
var observer = animationTree.Get("parameters/BlendSpace/observer").As<AnimationNodeObserverBlendSpace>();
observer.ClosestPointChanged += OnClosestPointChanged;
[/csharp]
[/codeblocks]
</description>
<tutorials>
<link title="Using AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
Expand Down
12 changes: 12 additions & 0 deletions doc/classes/AnimationNodeBlendSpace2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@
A resource used by [AnimationNodeBlendTree].
[AnimationNodeBlendSpace2D] represents a virtual 2D space on which [AnimationRootNode]s are placed. Outputs the linear blend of the three adjacent animations using a [Vector2] weight. Adjacent in this context means the three [AnimationRootNode]s making up the triangle that contains the current value.
You can add vertices to the blend space with [method add_blend_point] and automatically triangulate it by setting [member auto_triangles] to [code]true[/code]. Otherwise, use [method add_triangle] and [method remove_triangle] to triangulate the blend space by hand.

Optionally, signals can be used by setting an [AnimationNodeObserverBlendSpace] through [AnimationTree].
[codeblocks]
[gdscript]
var observer = tree.get("parameters/BlendSpace/observer")
observer.closest_point_changed.connect(on_closest_point_changed)
[/gdscript]
[csharp]
var observer = animationTree.Get("parameters/BlendSpace/observer").As&lt;AnimationNodeObserverBlendSpace&gt;();
observer.ClosestPointChanged += OnClosestPointChanged;
[/csharp]
[/codeblocks]
</description>
<tutorials>
<link title="Using AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
Expand Down
13 changes: 13 additions & 0 deletions doc/classes/AnimationNodeObserver.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationNodeObserver" inherits="Resource" api_type="core" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Base class for observer types which relay [AnimationNode] events for a particular [AnimationTree] node.
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<members>
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="true" />
</members>
</class>
18 changes: 18 additions & 0 deletions doc/classes/AnimationNodeObserverBlendSpace.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationNodeObserverBlendSpace" inherits="AnimationNodeObserver" api_type="core" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Observer for events from [AnimationNodeBlendSpace1D] and [AnimationNodeBlendSpace2D] instances.
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<signals>
<signal name="closest_point_changed">
<param index="0" name="closest_point_name" type="StringName" />
<description>
Emitted when the closest point to the current blend position changes.
</description>
</signal>
</signals>
</class>
32 changes: 32 additions & 0 deletions doc/classes/AnimationNodeObserverOneShot.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationNodeObserverOneShot" inherits="AnimationNodeObserver" api_type="core" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Observer for events from [AnimationNodeOneShot] instances.
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<signals>
<signal name="fade_in_finished">
<description>
Emitted when the one-shot has finished fading in. Only emitted if fade-in time is greater than zero.
</description>
</signal>
<signal name="fade_out_started">
<description>
Emitted when the one-shot has started fading out. Only emitted if fade-out time is greater than zero.
</description>
</signal>
<signal name="finished">
<description>
Emitted when the one-shot has finished.
</description>
</signal>
<signal name="started">
<description>
Emitted when the one-shot has started.
</description>
</signal>
</signals>
</class>
24 changes: 24 additions & 0 deletions doc/classes/AnimationNodeObserverTransition.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimationNodeObserverTransition" inherits="AnimationNodeObserver" api_type="core" experimental="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Observer for events from [AnimationNodeTransition] instances.
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
<signals>
<signal name="state_finished">
<param index="0" name="state" type="String" />
<description>
Emitted when transitioning out of a state. If crossfade time is greater than zero, emits when the crossfade finishes. Otherwise, emits immediately before [signal state_started] emits for the new state.
</description>
</signal>
<signal name="state_started">
<param index="0" name="state" type="String" />
<description>
Emitted when a transition to a new state starts.
</description>
</signal>
</signals>
</class>
11 changes: 11 additions & 0 deletions doc/classes/AnimationNodeOneShot.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@
animationTree.Get("parameters/OneShot/internal_active");
[/csharp]
[/codeblocks]
Optionally, signals can be used by setting an [AnimationNodeObserverOneShot] through [AnimationTree].
[codeblocks]
[gdscript]
var observer = tree.get("parameters/OneShot/observer")
observer.started.connect(on_one_shot_started)
[/gdscript]
[csharp]
var observer = animationTree.Get("parameters/OneShot/observer").As&lt;AnimationNodeObserverOneShot&gt;();
observer.Started += OnOneShotStarted;
[/csharp]
[/codeblocks]
</description>
<tutorials>
<link title="Using AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
Expand Down
11 changes: 11 additions & 0 deletions doc/classes/AnimationNodeTransition.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@
animationTree.Get("parameters/Transition/current_index");
[/csharp]
[/codeblocks]
Optionally, signals can be used by setting an [AnimationNodeObserverTransition] through [AnimationTree].
[codeblocks]
[gdscript]
var observer = animation_tree.get("parameters/Transition/observer")
observer.state_started.connect(on_state_started)
[/gdscript]
[csharp]
var observer = animationTree.Get("parameters/Transition/observer").As&lt;AnimationNodeObserverTransition&gt;();
observer.StateStarted += OnStateStarted;
[/csharp]
[/codeblocks]
</description>
<tutorials>
<link title="Using AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link>
Expand Down
8 changes: 8 additions & 0 deletions scene/animation/animation_blend_space_1d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
void AnimationNodeBlendSpace1D::get_parameter_list(LocalVector<PropertyInfo> *r_list) const {
AnimationNode::get_parameter_list(r_list);
r_list->push_back(PropertyInfo(Variant::FLOAT, blend_position));
r_list->push_back(PropertyInfo(Variant::OBJECT, observer, PROPERTY_HINT_RESOURCE_TYPE, AnimationNodeObserverBlendSpace::get_class_static(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ALWAYS_DUPLICATE));
r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
}

Expand Down Expand Up @@ -595,6 +596,13 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace1D::_process(ProcessState &p_
}
}

if (!p_test_only && new_closest != cur_closest && new_closest != -1) {
Ref<AnimationNodeObserverBlendSpace> observer_ref = p_instance.get_parameter_observer();
if (observer_ref.is_valid()) {
observer_ref->emit_signal("closest_point_changed", get_blend_point_name(new_closest));
}
}

p_instance.set_parameter_closest(new_closest, p_process_state.is_testing);
return mind;
}
Expand Down
8 changes: 8 additions & 0 deletions scene/animation/animation_blend_space_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
void AnimationNodeBlendSpace2D::get_parameter_list(LocalVector<PropertyInfo> *r_list) const {
AnimationNode::get_parameter_list(r_list);
r_list->push_back(PropertyInfo(Variant::VECTOR2, blend_position));
r_list->push_back(PropertyInfo(Variant::OBJECT, observer, PROPERTY_HINT_RESOURCE_TYPE, AnimationNodeObserverBlendSpace::get_class_static(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ALWAYS_DUPLICATE));
r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
}

Expand Down Expand Up @@ -755,6 +756,13 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace2D::_process(ProcessState &p_
}
}

if (!p_test_only && new_closest != cur_closest && new_closest != -1) {
Ref<AnimationNodeObserverBlendSpace> observer_ref = p_instance.get_parameter_observer();
if (observer_ref.is_valid()) {
observer_ref->emit_signal("closest_point_changed", get_blend_point_name(new_closest));
}
}

p_instance.set_parameter_closest(new_closest, p_process_state.is_testing);
return mind;
}
Expand Down
44 changes: 44 additions & 0 deletions scene/animation/animation_blend_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ void AnimationNodeOneShot::get_parameter_list(LocalVector<PropertyInfo> *r_list)
r_list->push_back(PropertyInfo(Variant::BOOL, active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY));
r_list->push_back(PropertyInfo(Variant::BOOL, internal_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY));
r_list->push_back(PropertyInfo(Variant::INT, request, PROPERTY_HINT_ENUM, ",Fire,Abort,Fade Out"));
r_list->push_back(PropertyInfo(Variant::OBJECT, observer, PROPERTY_HINT_RESOURCE_TYPE, AnimationNodeObserverOneShot::get_class_static(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ALWAYS_DUPLICATE));
r_list->push_back(PropertyInfo(Variant::FLOAT, fade_in_remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::FLOAT, fade_out_remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
Expand Down Expand Up @@ -560,6 +561,21 @@ bool AnimationNodeOneShot::has_filter() const {
return true;
}

void AnimationNodeOneShot::_check_and_notify_state_changes(AnimationNodeInstance &p_instance, bool p_prev_active, bool p_prev_internal_active, double p_prev_fade_in_remaining) {
Ref<AnimationNodeObserverOneShot> observer_ref = p_instance.get_parameter_observer();
if (observer_ref.is_valid()) {
if (!p_prev_active && p_instance.get_parameter_active()) {
observer_ref->emit_signal("started");
} else if (p_prev_active && !p_instance.get_parameter_active()) {
observer_ref->emit_signal(SceneStringName(finished));
} else if (Animation::is_greater_approx(p_prev_fade_in_remaining, 0) && Math::is_zero_approx(p_instance.get_parameter_fade_in_remaining())) {
observer_ref->emit_signal("fade_in_finished");
} else if (get_fade_out_time() > 0 && p_prev_internal_active && !p_instance.get_parameter_internal_active()) {
observer_ref->emit_signal("fade_out_started");
}
}
}

AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(ProcessState &p_process_state, AnimationNodeInstance &p_instance, const AnimationMixer::PlaybackInfo &p_playback_info, bool p_test_only) {
OneShotRequest cur_request = static_cast<OneShotRequest>(p_instance.get_parameter_request());
bool cur_active = p_instance.get_parameter_active();
Expand All @@ -579,6 +595,7 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(ProcessState &p_proce
double abs_delta = Math::abs(p_delta);
bool p_seek = p_playback_info.seeked;
bool p_is_external_seeking = p_playback_info.is_external_seeking;
double prev_fade_in_remaining = cur_fade_in_remaining;

bool do_start = cur_request == ONE_SHOT_REQUEST_FIRE;

Expand Down Expand Up @@ -628,6 +645,9 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(ProcessState &p_proce
bool os_seek = p_seek;

if (!is_shooting) {
if (!p_test_only) {
_check_and_notify_state_changes(p_instance, cur_active, cur_internal_active, prev_fade_in_remaining);
}
AnimationMixer::PlaybackInfo pi = p_playback_info;
pi.weight = 1.0;
return blend_input(p_process_state, p_instance, 0, pi, FILTER_IGNORE, sync, p_test_only);
Expand Down Expand Up @@ -728,6 +748,9 @@ AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(ProcessState &p_proce
p_instance.set_parameter_fade_in_remaining(cur_fade_in_remaining, p_process_state.is_testing);
p_instance.set_parameter_fade_out_remaining(cur_fade_out_remaining, p_process_state.is_testing);

if (!p_test_only) {
_check_and_notify_state_changes(p_instance, cur_active, cur_internal_active, prev_fade_in_remaining);
}
return cur_internal_active ? os_nti : main_nti;
}

Expand Down Expand Up @@ -1165,6 +1188,7 @@ void AnimationNodeTransition::get_parameter_list(LocalVector<PropertyInfo> *r_li
r_list->push_back(PropertyInfo(Variant::INT, current_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY)); // To avoid finding the index every frame, use this internally.
r_list->push_back(PropertyInfo(Variant::INT, prev_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::FLOAT, prev_xfading, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::OBJECT, observer, PROPERTY_HINT_RESOURCE_TYPE, AnimationNodeObserverTransition::get_class_static(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ALWAYS_DUPLICATE));
}

Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
Expand Down Expand Up @@ -1287,6 +1311,16 @@ bool AnimationNodeTransition::is_allow_transition_to_self() const {
return allow_transition_to_self;
}

void AnimationNodeTransition::_signal_state_change(const AnimationNodeInstance &p_instance, bool p_starting, int p_state, bool p_test_only) {
if (p_test_only) {
return;
}
Ref<AnimationNodeObserverTransition> observer_ref = p_instance.get_parameter_observer();
if (observer_ref.is_valid()) {
observer_ref->emit_signal(p_starting ? SceneStringName(state_started) : SceneStringName(state_finished), get_input_name(p_state));
}
}

AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(ProcessState &p_process_state, AnimationNodeInstance &p_instance, const AnimationMixer::PlaybackInfo &p_playback_info, bool p_test_only) {
const String &cur_transition_request = p_instance.get_parameter_transition_request();
int cur_current_index = p_instance.get_parameter_current_index();
Expand Down Expand Up @@ -1333,6 +1367,10 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(ProcessState &p_pr
}
} else {
switched = true;
if (xfade_time == 0) {
_signal_state_change(p_instance, false, cur_current_index, p_test_only);
}
_signal_state_change(p_instance, true, new_idx, p_test_only);
cur_prev_index = cur_current_index;
p_instance.set_parameter_prev_index(cur_current_index, p_process_state.is_testing);
cur_current_index = new_idx;
Expand All @@ -1346,6 +1384,9 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(ProcessState &p_pr
}

if (clear_remaining_fade) {
if (xfade_time > 0 && Animation::is_greater_approx(cur_prev_xfading, 0.0)) {
_signal_state_change(p_instance, false, cur_prev_index, p_test_only);
}
cur_prev_xfading = 0;
p_instance.set_parameter_prev_xfading(0, p_process_state.is_testing);
cur_prev_index = -1;
Expand Down Expand Up @@ -1416,6 +1457,9 @@ AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(ProcessState &p_pr
blend_input(p_process_state, p_instance, cur_prev_index, pi, FILTER_IGNORE, true, p_test_only);
if (!p_seek) {
if (Animation::is_less_or_equal_approx(cur_prev_xfading, 0)) {
if (xfade_time > 0) {
_signal_state_change(p_instance, false, cur_prev_index, p_test_only);
}
p_instance.set_parameter_prev_index(-1, p_process_state.is_testing);
}
cur_prev_xfading -= Math::abs(p_playback_info.delta);
Expand Down
26 changes: 26 additions & 0 deletions scene/animation/animation_blend_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,18 @@ class AnimationNodeSync : public AnimationNode {
AnimationNodeSync();
};

class AnimationNodeObserverOneShot : public AnimationNodeObserver {
GDCLASS(AnimationNodeObserverOneShot, AnimationNodeObserver);

protected:
static void _bind_methods() {
ADD_SIGNAL(MethodInfo("started"));
ADD_SIGNAL(MethodInfo("fade_in_finished"));
ADD_SIGNAL(MethodInfo("fade_out_started"));
ADD_SIGNAL(MethodInfo(SceneStringName(finished)));
}
};

class AnimationNodeOneShot : public AnimationNodeSync {
GDCLASS(AnimationNodeOneShot, AnimationNodeSync);

Expand Down Expand Up @@ -160,6 +172,8 @@ class AnimationNodeOneShot : public AnimationNodeSync {
StringName fade_out_remaining = "fade_out_remaining";
StringName time_to_restart = "time_to_restart";

void _check_and_notify_state_changes(AnimationNodeInstance &p_instance, bool p_prev_active, bool p_prev_internal_active, double p_prev_fade_in_remaining);

protected:
static void _bind_methods();

Expand Down Expand Up @@ -329,6 +343,16 @@ class AnimationNodeTimeSeek : public AnimationNode {
AnimationNodeTimeSeek();
};

class AnimationNodeObserverTransition : public AnimationNodeObserver {
GDCLASS(AnimationNodeObserverTransition, AnimationNodeObserver);

protected:
static void _bind_methods() {
ADD_SIGNAL(MethodInfo(SceneStringName(state_started), PropertyInfo(Variant::STRING, "state")));
ADD_SIGNAL(MethodInfo(SceneStringName(state_finished), PropertyInfo(Variant::STRING, "state")));
}
};

class AnimationNodeTransition : public AnimationNodeSync {
GDCLASS(AnimationNodeTransition, AnimationNodeSync);

Expand All @@ -351,6 +375,8 @@ class AnimationNodeTransition : public AnimationNodeSync {

bool pending_update = false;

void _signal_state_change(const AnimationNodeInstance &p_instance, bool p_starting, int p_state, bool p_test_only);

protected:
bool _get(const StringName &p_path, Variant &r_ret) const;
bool _set(const StringName &p_path, const Variant &p_value);
Expand Down
3 changes: 3 additions & 0 deletions scene/animation/animation_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter
if (p_parameter == current_length || p_parameter == current_position || p_parameter == current_delta) {
return 0.0;
}
if (p_parameter == observer) {
return Ref<AnimationNodeObserver>();
}
GDVIRTUAL_CALL(_get_parameter_default_value, p_parameter, ret);
return ret;
}
Expand Down
Loading
Loading