Rework StateMachine and nested StateMachine process
Breaking compatibility: If a StateMachineTransition is connected to a nested StateMachine prior to this, it is removed. Also, there was a feature to connect another StateMachine as the End of a StateMachine, which is also removed to avoid reference confusion. It was like a GoTo Statement, also further passing the same reference to the blending process, causing the blending calculation to break or causing some StateMachines to not work.
This commit is contained in:
parent
a7d0e18a31
commit
991e6e90ba
|
@ -61,6 +61,7 @@
|
||||||
<param index="0" name="time" type="float" />
|
<param index="0" name="time" type="float" />
|
||||||
<param index="1" name="seek" type="bool" />
|
<param index="1" name="seek" type="bool" />
|
||||||
<param index="2" name="is_external_seeking" type="bool" />
|
<param index="2" name="is_external_seeking" type="bool" />
|
||||||
|
<param index="3" name="test_only" type="bool" />
|
||||||
<description>
|
<description>
|
||||||
When inheriting from [AnimationRootNode], implement this virtual method to run some code when this node is processed. The [param time] parameter is a relative delta, unless [param seek] is [code]true[/code], in which case it is absolute.
|
When inheriting from [AnimationRootNode], implement this virtual method to run some code when this node is processed. The [param time] parameter is a relative delta, unless [param seek] is [code]true[/code], in which case it is absolute.
|
||||||
Here, call the [method blend_input], [method blend_node] or [method blend_animation] functions. You can also use [method get_parameter] and [method set_parameter] to modify local memory.
|
Here, call the [method blend_input], [method blend_node] or [method blend_animation] functions. You can also use [method get_parameter] and [method set_parameter] to modify local memory.
|
||||||
|
@ -97,6 +98,7 @@
|
||||||
<param index="4" name="blend" type="float" />
|
<param index="4" name="blend" type="float" />
|
||||||
<param index="5" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
|
<param index="5" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
|
||||||
<param index="6" name="sync" type="bool" default="true" />
|
<param index="6" name="sync" type="bool" default="true" />
|
||||||
|
<param index="7" name="test_only" type="bool" default="false" />
|
||||||
<description>
|
<description>
|
||||||
Blend an input. This is only useful for nodes created for an [AnimationNodeBlendTree]. The [param time] parameter is a relative delta, unless [param seek] is [code]true[/code], in which case it is absolute. A filter mode may be optionally passed (see [enum FilterAction] for options).
|
Blend an input. This is only useful for nodes created for an [AnimationNodeBlendTree]. The [param time] parameter is a relative delta, unless [param seek] is [code]true[/code], in which case it is absolute. A filter mode may be optionally passed (see [enum FilterAction] for options).
|
||||||
</description>
|
</description>
|
||||||
|
@ -111,6 +113,7 @@
|
||||||
<param index="5" name="blend" type="float" />
|
<param index="5" name="blend" type="float" />
|
||||||
<param index="6" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
|
<param index="6" name="filter" type="int" enum="AnimationNode.FilterAction" default="0" />
|
||||||
<param index="7" name="sync" type="bool" default="true" />
|
<param index="7" name="sync" type="bool" default="true" />
|
||||||
|
<param index="8" name="test_only" type="bool" default="false" />
|
||||||
<description>
|
<description>
|
||||||
Blend another animation node (in case this node contains children animation nodes). This function is only useful if you inherit from [AnimationRootNode] instead, else editors will not display your node for addition.
|
Blend another animation node (in case this node contains children animation nodes). This function is only useful if you inherit from [AnimationRootNode] instead, else editors will not display your node for addition.
|
||||||
</description>
|
</description>
|
||||||
|
|
|
@ -165,5 +165,23 @@
|
||||||
<member name="allow_transition_to_self" type="bool" setter="set_allow_transition_to_self" getter="is_allow_transition_to_self" default="false">
|
<member name="allow_transition_to_self" type="bool" setter="set_allow_transition_to_self" getter="is_allow_transition_to_self" default="false">
|
||||||
If [code]true[/code], allows teleport to the self state with [method AnimationNodeStateMachinePlayback.travel]. When the reset option is enabled in [method AnimationNodeStateMachinePlayback.travel], the animation is restarted. If [code]false[/code], nothing happens on the teleportation to the self state.
|
If [code]true[/code], allows teleport to the self state with [method AnimationNodeStateMachinePlayback.travel]. When the reset option is enabled in [method AnimationNodeStateMachinePlayback.travel], the animation is restarted. If [code]false[/code], nothing happens on the teleportation to the self state.
|
||||||
</member>
|
</member>
|
||||||
|
<member name="reset_ends" type="bool" setter="set_reset_ends" getter="are_ends_reset" default="false">
|
||||||
|
If [code]true[/code], treat the cross-fade to the start and end nodes as a blend with the RESET animation.
|
||||||
|
In most cases, when additional cross-fades are performed in the parent [AnimationNode] of the state machine, setting this property to [code]false[/code] and matching the cross-fade time of the parent [AnimationNode] and the state machine's start node and end node gives good results.
|
||||||
|
</member>
|
||||||
|
<member name="state_machine_type" type="int" setter="set_state_machine_type" getter="get_state_machine_type" enum="AnimationNodeStateMachine.StateMachineType" default="0">
|
||||||
|
This property can define the process of transitions for different use cases. See also [enum AnimationNodeStateMachine.StateMachineType].
|
||||||
|
</member>
|
||||||
</members>
|
</members>
|
||||||
|
<constants>
|
||||||
|
<constant name="STATE_MACHINE_TYPE_ROOT" value="0" enum="StateMachineType">
|
||||||
|
Seeking to the beginning is treated as playing from the start state. Transition to the end state is treated as exiting the state machine.
|
||||||
|
</constant>
|
||||||
|
<constant name="STATE_MACHINE_TYPE_NESTED" value="1" enum="StateMachineType">
|
||||||
|
Seeking to the beginning is treated as seeking to the beginning of the animation in the current state. Transition to the end state, or the absence of transitions in each state, is treated as exiting the state machine.
|
||||||
|
</constant>
|
||||||
|
<constant name="STATE_MACHINE_TYPE_GROUPED" value="2" enum="StateMachineType">
|
||||||
|
This is a grouped state machine that can be controlled from a parent state machine. It does not work on standalone. There must be a state machine with [member state_machine_type] of [constant STATE_MACHINE_TYPE_ROOT] or [constant STATE_MACHINE_TYPE_NESTED] in the parent or ancestor.
|
||||||
|
</constant>
|
||||||
|
</constants>
|
||||||
</class>
|
</class>
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include "scene/gui/tree.h"
|
#include "scene/gui/tree.h"
|
||||||
#include "scene/main/viewport.h"
|
#include "scene/main/viewport.h"
|
||||||
#include "scene/main/window.h"
|
#include "scene/main/window.h"
|
||||||
|
#include "scene/scene_string_names.h"
|
||||||
|
|
||||||
bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node) {
|
bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node) {
|
||||||
Ref<AnimationNodeStateMachine> ansm = p_node;
|
Ref<AnimationNodeStateMachine> ansm = p_node;
|
||||||
|
@ -67,7 +68,6 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
|
||||||
selected_transition_from = StringName();
|
selected_transition_from = StringName();
|
||||||
selected_transition_to = StringName();
|
selected_transition_to = StringName();
|
||||||
selected_transition_index = -1;
|
selected_transition_index = -1;
|
||||||
selected_multi_transition = TransitionLine();
|
|
||||||
selected_node = StringName();
|
selected_node = StringName();
|
||||||
selected_nodes.clear();
|
selected_nodes.clear();
|
||||||
_update_mode();
|
_update_mode();
|
||||||
|
@ -78,14 +78,60 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) {
|
||||||
tool_connect->set_disabled(read_only);
|
tool_connect->set_disabled(read_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String AnimationNodeStateMachineEditor::_get_root_playback_path(String &r_node_directory) {
|
||||||
|
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
|
||||||
|
Vector<String> edited_path = AnimationTreeEditor::get_singleton()->get_edited_path();
|
||||||
|
|
||||||
|
String base_path;
|
||||||
|
Vector<String> node_directory_path;
|
||||||
|
|
||||||
|
bool is_playable_anodesm_found = false;
|
||||||
|
|
||||||
|
if (edited_path.size()) {
|
||||||
|
while (!is_playable_anodesm_found) {
|
||||||
|
base_path = String("/").join(edited_path);
|
||||||
|
Ref<AnimationNodeStateMachine> anodesm = !edited_path.size() ? tree->get_tree_root() : tree->get_tree_root()->find_node_by_path(base_path);
|
||||||
|
if (!anodesm.is_valid()) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if (anodesm->get_state_machine_type() != AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) {
|
||||||
|
is_playable_anodesm_found = true;
|
||||||
|
} else {
|
||||||
|
int idx = edited_path.size() - 1;
|
||||||
|
node_directory_path.push_back(edited_path[idx]);
|
||||||
|
edited_path.remove_at(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_playable_anodesm_found) {
|
||||||
|
// Return Root/Nested state machine playback.
|
||||||
|
node_directory_path.reverse();
|
||||||
|
r_node_directory = String("/").join(node_directory_path);
|
||||||
|
if (node_directory_path.size()) {
|
||||||
|
r_node_directory += "/";
|
||||||
|
}
|
||||||
|
base_path = !edited_path.size() ? String(SceneStringNames::get_singleton()->parameters_base_path) + "playback" : String(SceneStringNames::get_singleton()->parameters_base_path) + base_path + "/playback";
|
||||||
|
} else {
|
||||||
|
// Hmmm, we have to return Grouped state machine playback...
|
||||||
|
// It will give the user the error that Root/Nested state machine should be retrieved, that would be kind :-)
|
||||||
|
r_node_directory = String();
|
||||||
|
base_path = AnimationTreeEditor::get_singleton()->get_base_path() + "playback";
|
||||||
|
}
|
||||||
|
|
||||||
|
return base_path;
|
||||||
|
}
|
||||||
|
|
||||||
void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) {
|
void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) {
|
||||||
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
|
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
|
||||||
if (!tree) {
|
if (!tree) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
|
String node_directory;
|
||||||
if (playback.is_null()) {
|
Ref<AnimationNodeStateMachinePlayback> playback = tree->get(_get_root_playback_path(node_directory));
|
||||||
|
if (!playback.is_valid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,16 +145,6 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group selected nodes on a state machine
|
|
||||||
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->is_ctrl_pressed() && !k->is_shift_pressed() && k->get_keycode() == Key::G && !k->is_echo()) {
|
|
||||||
_group_selected_nodes();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ungroup state machine
|
|
||||||
if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->is_ctrl_pressed() && k->is_shift_pressed() && k->get_keycode() == Key::G && !k->is_echo()) {
|
|
||||||
_ungroup_selected_nodes();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<InputEventMouseButton> mb = p_event;
|
Ref<InputEventMouseButton> mb = p_event;
|
||||||
|
|
||||||
// Add new node
|
// Add new node
|
||||||
|
@ -124,17 +160,16 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
|
||||||
selected_transition_from = StringName();
|
selected_transition_from = StringName();
|
||||||
selected_transition_to = StringName();
|
selected_transition_to = StringName();
|
||||||
selected_transition_index = -1;
|
selected_transition_index = -1;
|
||||||
selected_multi_transition = TransitionLine();
|
|
||||||
selected_node = StringName();
|
selected_node = StringName();
|
||||||
|
|
||||||
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
|
for (int i = node_rects.size() - 1; i >= 0; i--) { //inverse to draw order
|
||||||
if (node_rects[i].play.has_point(mb->get_position())) { //edit name
|
if (node_rects[i].play.has_point(mb->get_position())) { //edit name
|
||||||
if (play_mode->get_selected() == 1 || !playback->is_playing()) {
|
if (play_mode->get_selected() == 1 || !playback->is_playing()) {
|
||||||
//start
|
// Start
|
||||||
playback->start(node_rects[i].node_name);
|
playback->start(node_directory + String(node_rects[i].node_name));
|
||||||
} else {
|
} else {
|
||||||
//travel
|
// Travel
|
||||||
playback->travel(node_rects[i].node_name);
|
playback->travel(node_directory + String(node_rects[i].node_name));
|
||||||
}
|
}
|
||||||
state_machine_draw->queue_redraw();
|
state_machine_draw->queue_redraw();
|
||||||
return;
|
return;
|
||||||
|
@ -213,26 +248,11 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
|
||||||
selected_transition_index = closest;
|
selected_transition_index = closest;
|
||||||
|
|
||||||
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(closest);
|
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(closest);
|
||||||
EditorNode::get_singleton()->push_item(tr.ptr(), "", true);
|
if (!state_machine->is_transition_across_group(closest)) {
|
||||||
|
EditorNode::get_singleton()->push_item(tr.ptr(), "", true);
|
||||||
if (!transition_lines[closest].multi_transitions.is_empty()) {
|
} else {
|
||||||
selected_transition_index = -1;
|
EditorNode::get_singleton()->push_item(tr.ptr(), "", true);
|
||||||
selected_multi_transition = transition_lines[closest];
|
EditorNode::get_singleton()->push_item(nullptr, "", true);
|
||||||
|
|
||||||
Ref<EditorAnimationMultiTransitionEdit> multi;
|
|
||||||
multi.instantiate();
|
|
||||||
multi->add_transition(selected_transition_from, selected_transition_to, tr);
|
|
||||||
|
|
||||||
for (int i = 0; i < transition_lines[closest].multi_transitions.size(); i++) {
|
|
||||||
int index = transition_lines[closest].multi_transitions[i].transition_index;
|
|
||||||
|
|
||||||
Ref<AnimationNodeStateMachineTransition> transition = state_machine->get_transition(index);
|
|
||||||
StringName from = transition_lines[closest].multi_transitions[i].from_node;
|
|
||||||
StringName to = transition_lines[closest].multi_transitions[i].to_node;
|
|
||||||
|
|
||||||
multi->add_transition(from, to, transition);
|
|
||||||
}
|
|
||||||
EditorNode::get_singleton()->push_item(multi.ptr(), "", true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,11 +316,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
|
||||||
EditorNode::get_singleton()->show_warning(TTR("Transition exists!"));
|
EditorNode::get_singleton()->show_warning(TTR("Transition exists!"));
|
||||||
connecting = false;
|
connecting = false;
|
||||||
} else {
|
} else {
|
||||||
if (anodesm.is_valid() || end_node.is_valid()) {
|
_add_transition();
|
||||||
_open_connect_menu(mb->get_position());
|
|
||||||
} else {
|
|
||||||
_add_transition();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_open_menu(mb->get_position());
|
_open_menu(mb->get_position());
|
||||||
|
@ -481,12 +497,6 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
|
||||||
String from = String(transition_lines[closest].from_node);
|
String from = String(transition_lines[closest].from_node);
|
||||||
String to = String(transition_lines[closest].to_node);
|
String to = String(transition_lines[closest].to_node);
|
||||||
String tooltip = from + " -> " + to;
|
String tooltip = from + " -> " + to;
|
||||||
|
|
||||||
for (int i = 0; i < transition_lines[closest].multi_transitions.size(); i++) {
|
|
||||||
from = String(transition_lines[closest].multi_transitions[i].from_node);
|
|
||||||
to = String(transition_lines[closest].multi_transitions[i].to_node);
|
|
||||||
tooltip += "\n" + from + " -> " + to;
|
|
||||||
}
|
|
||||||
state_machine_draw->set_tooltip_text(tooltip);
|
state_machine_draw->set_tooltip_text(tooltip);
|
||||||
} else {
|
} else {
|
||||||
state_machine_draw->set_tooltip_text("");
|
state_machine_draw->set_tooltip_text("");
|
||||||
|
@ -522,224 +532,6 @@ Control::CursorShape AnimationNodeStateMachineEditor::get_cursor_shape(const Poi
|
||||||
return cursor_shape;
|
return cursor_shape;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationNodeStateMachineEditor::_group_selected_nodes() {
|
|
||||||
if (!selected_nodes.is_empty()) {
|
|
||||||
if (selected_nodes.size() == 1 && (*selected_nodes.begin() == state_machine->start_node || *selected_nodes.begin() == state_machine->end_node))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Ref<AnimationNodeStateMachine> group_sm = memnew(AnimationNodeStateMachine);
|
|
||||||
Vector2 group_position;
|
|
||||||
|
|
||||||
Vector<NodeUR> nodes_ur;
|
|
||||||
Vector<TransitionUR> transitions_ur;
|
|
||||||
|
|
||||||
int base = 1;
|
|
||||||
String base_name = group_sm->get_caption();
|
|
||||||
String group_name = base_name;
|
|
||||||
|
|
||||||
while (state_machine->has_node(group_name) && !selected_nodes.has(group_name)) {
|
|
||||||
base++;
|
|
||||||
group_name = base_name + " " + itos(base);
|
|
||||||
}
|
|
||||||
|
|
||||||
updating = true;
|
|
||||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
|
||||||
undo_redo->create_action("Group");
|
|
||||||
|
|
||||||
// Move selected nodes to the new state machine
|
|
||||||
for (const StringName &E : selected_nodes) {
|
|
||||||
if (!state_machine->can_edit_node(E)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<AnimationNode> node = state_machine->get_node(E);
|
|
||||||
Vector2 node_position = state_machine->get_node_position(E);
|
|
||||||
group_position += node_position;
|
|
||||||
|
|
||||||
NodeUR new_node;
|
|
||||||
new_node.name = E;
|
|
||||||
new_node.node = node;
|
|
||||||
new_node.position = node_position;
|
|
||||||
|
|
||||||
nodes_ur.push_back(new_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the transitions to the new state machine
|
|
||||||
for (int i = 0; i < state_machine->get_transition_count(); i++) {
|
|
||||||
String from = state_machine->get_transition_from(i);
|
|
||||||
String to = state_machine->get_transition_to(i);
|
|
||||||
|
|
||||||
String local_from = from.get_slicec('/', 0);
|
|
||||||
String local_to = to.get_slicec('/', 0);
|
|
||||||
|
|
||||||
String old_from = from;
|
|
||||||
String old_to = to;
|
|
||||||
|
|
||||||
bool from_selected = false;
|
|
||||||
bool to_selected = false;
|
|
||||||
|
|
||||||
if (selected_nodes.has(local_from) && local_from != state_machine->start_node) {
|
|
||||||
from_selected = true;
|
|
||||||
}
|
|
||||||
if (selected_nodes.has(local_to) && local_to != state_machine->end_node) {
|
|
||||||
to_selected = true;
|
|
||||||
}
|
|
||||||
if (!from_selected && !to_selected) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i);
|
|
||||||
|
|
||||||
if (!from_selected) {
|
|
||||||
from = "../" + old_from;
|
|
||||||
}
|
|
||||||
if (!to_selected) {
|
|
||||||
to = "../" + old_to;
|
|
||||||
}
|
|
||||||
|
|
||||||
TransitionUR new_tr;
|
|
||||||
new_tr.new_from = from;
|
|
||||||
new_tr.new_to = to;
|
|
||||||
new_tr.old_from = old_from;
|
|
||||||
new_tr.old_to = old_to;
|
|
||||||
new_tr.transition = tr;
|
|
||||||
|
|
||||||
transitions_ur.push_back(new_tr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < nodes_ur.size(); i++) {
|
|
||||||
undo_redo->add_do_method(state_machine.ptr(), "remove_node", nodes_ur[i].name);
|
|
||||||
undo_redo->add_undo_method(group_sm.ptr(), "remove_node", nodes_ur[i].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
undo_redo->add_do_method(state_machine.ptr(), "add_node", group_name, group_sm, group_position / nodes_ur.size());
|
|
||||||
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", group_name);
|
|
||||||
|
|
||||||
for (int i = 0; i < nodes_ur.size(); i++) {
|
|
||||||
undo_redo->add_do_method(group_sm.ptr(), "add_node", nodes_ur[i].name, nodes_ur[i].node, nodes_ur[i].position);
|
|
||||||
undo_redo->add_undo_method(state_machine.ptr(), "add_node", nodes_ur[i].name, nodes_ur[i].node, nodes_ur[i].position);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < transitions_ur.size(); i++) {
|
|
||||||
undo_redo->add_do_method(group_sm.ptr(), "add_transition", transitions_ur[i].new_from, transitions_ur[i].new_to, transitions_ur[i].transition);
|
|
||||||
undo_redo->add_undo_method(state_machine.ptr(), "add_transition", transitions_ur[i].old_from, transitions_ur[i].old_to, transitions_ur[i].transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
undo_redo->add_do_method(this, "_update_graph");
|
|
||||||
undo_redo->add_undo_method(this, "_update_graph");
|
|
||||||
undo_redo->commit_action();
|
|
||||||
updating = false;
|
|
||||||
|
|
||||||
selected_nodes.clear();
|
|
||||||
selected_nodes.insert(group_name);
|
|
||||||
state_machine_draw->queue_redraw();
|
|
||||||
accept_event();
|
|
||||||
_update_mode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimationNodeStateMachineEditor::_ungroup_selected_nodes() {
|
|
||||||
bool find = false;
|
|
||||||
HashSet<StringName> new_selected_nodes;
|
|
||||||
|
|
||||||
for (const StringName &E : selected_nodes) {
|
|
||||||
Ref<AnimationNodeStateMachine> group_sm = state_machine->get_node(E);
|
|
||||||
|
|
||||||
if (group_sm.is_valid()) {
|
|
||||||
find = true;
|
|
||||||
|
|
||||||
Vector2 group_position = state_machine->get_node_position(E);
|
|
||||||
StringName group_name = E;
|
|
||||||
|
|
||||||
List<AnimationNode::ChildNode> nodes;
|
|
||||||
group_sm->get_child_nodes(&nodes);
|
|
||||||
|
|
||||||
Vector<NodeUR> nodes_ur;
|
|
||||||
Vector<TransitionUR> transitions_ur;
|
|
||||||
|
|
||||||
updating = true;
|
|
||||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
|
||||||
undo_redo->create_action("Ungroup");
|
|
||||||
|
|
||||||
// Move all child nodes to current state machine
|
|
||||||
for (int i = 0; i < nodes.size(); i++) {
|
|
||||||
if (!group_sm->can_edit_node(nodes[i].name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2 node_position = group_sm->get_node_position(nodes[i].name);
|
|
||||||
|
|
||||||
NodeUR new_node;
|
|
||||||
new_node.name = nodes[i].name;
|
|
||||||
new_node.position = node_position;
|
|
||||||
new_node.node = nodes[i].node;
|
|
||||||
|
|
||||||
nodes_ur.push_back(new_node);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < group_sm->get_transition_count(); i++) {
|
|
||||||
String from = group_sm->get_transition_from(i);
|
|
||||||
String to = group_sm->get_transition_to(i);
|
|
||||||
Ref<AnimationNodeStateMachineTransition> tr = group_sm->get_transition(i);
|
|
||||||
|
|
||||||
TransitionUR new_tr;
|
|
||||||
new_tr.new_from = from.replace_first("../", "");
|
|
||||||
new_tr.new_to = to.replace_first("../", "");
|
|
||||||
new_tr.old_from = from;
|
|
||||||
new_tr.old_to = to;
|
|
||||||
new_tr.transition = tr;
|
|
||||||
|
|
||||||
transitions_ur.push_back(new_tr);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < nodes_ur.size(); i++) {
|
|
||||||
undo_redo->add_do_method(group_sm.ptr(), "remove_node", nodes_ur[i].name);
|
|
||||||
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", nodes_ur[i].name);
|
|
||||||
}
|
|
||||||
|
|
||||||
undo_redo->add_do_method(state_machine.ptr(), "remove_node", group_name);
|
|
||||||
undo_redo->add_undo_method(state_machine.ptr(), "add_node", group_name, group_sm, group_position);
|
|
||||||
|
|
||||||
for (int i = 0; i < nodes_ur.size(); i++) {
|
|
||||||
new_selected_nodes.insert(nodes_ur[i].name);
|
|
||||||
undo_redo->add_do_method(state_machine.ptr(), "add_node", nodes_ur[i].name, nodes_ur[i].node, nodes_ur[i].position);
|
|
||||||
undo_redo->add_undo_method(group_sm.ptr(), "add_node", nodes_ur[i].name, nodes_ur[i].node, nodes_ur[i].position);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < transitions_ur.size(); i++) {
|
|
||||||
if (transitions_ur[i].old_from != state_machine->start_node && transitions_ur[i].old_to != state_machine->end_node) {
|
|
||||||
undo_redo->add_do_method(state_machine.ptr(), "add_transition", transitions_ur[i].new_from, transitions_ur[i].new_to, transitions_ur[i].transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
undo_redo->add_undo_method(group_sm.ptr(), "add_transition", transitions_ur[i].old_from, transitions_ur[i].old_to, transitions_ur[i].transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < state_machine->get_transition_count(); i++) {
|
|
||||||
String from = state_machine->get_transition_from(i);
|
|
||||||
String to = state_machine->get_transition_to(i);
|
|
||||||
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i);
|
|
||||||
|
|
||||||
if (from == group_name || to == group_name) {
|
|
||||||
undo_redo->add_undo_method(state_machine.ptr(), "add_transition", from, to, tr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
undo_redo->add_do_method(this, "_update_graph");
|
|
||||||
undo_redo->add_undo_method(this, "_update_graph");
|
|
||||||
undo_redo->commit_action();
|
|
||||||
updating = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (find) {
|
|
||||||
selected_nodes = new_selected_nodes;
|
|
||||||
selected_node = StringName();
|
|
||||||
state_machine_draw->queue_redraw();
|
|
||||||
accept_event();
|
|
||||||
_update_mode();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) {
|
void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) {
|
||||||
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
|
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
|
||||||
if (!tree) {
|
if (!tree) {
|
||||||
|
@ -790,83 +582,8 @@ void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) {
|
||||||
add_node_pos = p_position / EDSCALE + state_machine->get_graph_offset();
|
add_node_pos = p_position / EDSCALE + state_machine->get_graph_offset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationNodeStateMachineEditor::_open_connect_menu(const Vector2 &p_position) {
|
bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<AnimationNodeStateMachine> p_nodesm, const StringName &p_name, const StringName &p_path) {
|
||||||
ERR_FAIL_COND(connecting_to_node == StringName());
|
|
||||||
|
|
||||||
Ref<AnimationNode> node = state_machine->get_node(connecting_to_node);
|
|
||||||
Ref<AnimationNodeStateMachine> anodesm = node;
|
|
||||||
Ref<AnimationNodeEndState> end_node = node;
|
|
||||||
ERR_FAIL_COND(!anodesm.is_valid() && !end_node.is_valid());
|
|
||||||
|
|
||||||
connect_menu->clear();
|
|
||||||
state_machine_menu->clear();
|
|
||||||
end_menu->clear();
|
|
||||||
nodes_to_connect.clear();
|
|
||||||
|
|
||||||
for (int i = connect_menu->get_child_count() - 1; i >= 0; i--) {
|
|
||||||
Node *child = connect_menu->get_child(i);
|
|
||||||
|
|
||||||
if (child->is_class("PopupMenu")) {
|
|
||||||
connect_menu->remove_child(child);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
connect_menu->reset_size();
|
|
||||||
state_machine_menu->reset_size();
|
|
||||||
end_menu->reset_size();
|
|
||||||
|
|
||||||
if (anodesm.is_valid()) {
|
|
||||||
_create_submenu(connect_menu, anodesm, connecting_to_node, connecting_to_node);
|
|
||||||
} else {
|
|
||||||
_create_submenu(connect_menu, state_machine, connecting_to_node, connecting_to_node, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect_menu->add_submenu_item(TTR("To") + " Animation", connecting_to_node);
|
|
||||||
|
|
||||||
if (state_machine_menu->get_item_count() > 0 || !end_node.is_valid()) {
|
|
||||||
connect_menu->add_submenu_item(TTR("To") + " StateMachine", "state_machines");
|
|
||||||
connect_menu->add_child(state_machine_menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end_node.is_valid()) {
|
|
||||||
connect_menu->add_submenu_item(TTR("To") + " End", "end_nodes");
|
|
||||||
connect_menu->add_child(end_menu);
|
|
||||||
} else {
|
|
||||||
state_machine_menu->add_item(connecting_to_node, nodes_to_connect.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes_to_connect.push_back(connecting_to_node);
|
|
||||||
|
|
||||||
if (nodes_to_connect.size() == 1) {
|
|
||||||
_add_transition();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
connect_menu->set_position(state_machine_draw->get_screen_transform().xform(p_position));
|
|
||||||
connect_menu->popup();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<AnimationNodeStateMachine> p_nodesm, const StringName &p_name, const StringName &p_path, bool from_root, Vector<Ref<AnimationNodeStateMachine>> p_parents) {
|
|
||||||
String prev_path;
|
String prev_path;
|
||||||
Vector<Ref<AnimationNodeStateMachine>> parents = p_parents;
|
|
||||||
|
|
||||||
if (from_root && p_nodesm->get_prev_state_machine() == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (from_root) {
|
|
||||||
AnimationNodeStateMachine *prev = p_nodesm->get_prev_state_machine();
|
|
||||||
|
|
||||||
while (prev != nullptr) {
|
|
||||||
parents.push_back(prev);
|
|
||||||
p_nodesm = Ref<AnimationNodeStateMachine>(prev);
|
|
||||||
prev_path += "../";
|
|
||||||
prev = prev->get_prev_state_machine();
|
|
||||||
}
|
|
||||||
end_menu->add_item("Root", nodes_to_connect.size());
|
|
||||||
nodes_to_connect.push_back(prev_path + state_machine->end_node);
|
|
||||||
prev_path.remove_at(prev_path.size() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
List<StringName> nodes;
|
List<StringName> nodes;
|
||||||
p_nodesm->get_node_list(&nodes);
|
p_nodesm->get_node_list(&nodes);
|
||||||
|
@ -881,12 +598,7 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
|
||||||
if (p_nodesm->can_edit_node(E)) {
|
if (p_nodesm->can_edit_node(E)) {
|
||||||
Ref<AnimationNodeStateMachine> ansm = p_nodesm->get_node(E);
|
Ref<AnimationNodeStateMachine> ansm = p_nodesm->get_node(E);
|
||||||
|
|
||||||
String path;
|
String path = String(p_path) + "/" + E;
|
||||||
if (from_root) {
|
|
||||||
path = prev_path + "/" + E;
|
|
||||||
} else {
|
|
||||||
path = String(p_path) + "/" + E;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ansm == state_machine) {
|
if (ansm == state_machine) {
|
||||||
end_menu->add_item(E, nodes_to_connect.size());
|
end_menu->add_item(E, nodes_to_connect.size());
|
||||||
|
@ -895,25 +607,10 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ansm.is_valid()) {
|
if (ansm.is_valid()) {
|
||||||
bool parent_found = false;
|
state_machine_menu->add_item(E, nodes_to_connect.size());
|
||||||
|
nodes_to_connect.push_back(path);
|
||||||
|
|
||||||
for (int i = 0; i < parents.size(); i++) {
|
if (_create_submenu(nodes_menu, ansm, E, path)) {
|
||||||
if (parents[i] == ansm) {
|
|
||||||
path = path.replace_first("/../" + E, "");
|
|
||||||
parent_found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent_found) {
|
|
||||||
end_menu->add_item(E, nodes_to_connect.size());
|
|
||||||
nodes_to_connect.push_back(path + "/" + state_machine->end_node);
|
|
||||||
} else {
|
|
||||||
state_machine_menu->add_item(E, nodes_to_connect.size());
|
|
||||||
nodes_to_connect.push_back(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_create_submenu(nodes_menu, ansm, E, path, false, parents)) {
|
|
||||||
nodes_menu->add_submenu_item(E, E);
|
nodes_menu->add_submenu_item(E, E);
|
||||||
node_added = true;
|
node_added = true;
|
||||||
}
|
}
|
||||||
|
@ -939,7 +636,6 @@ void AnimationNodeStateMachineEditor::_delete_selected() {
|
||||||
while (item) {
|
while (item) {
|
||||||
if (!updating) {
|
if (!updating) {
|
||||||
updating = true;
|
updating = true;
|
||||||
selected_multi_transition = TransitionLine();
|
|
||||||
undo_redo->create_action("Transition(s) Removed");
|
undo_redo->create_action("Transition(s) Removed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -959,18 +655,10 @@ void AnimationNodeStateMachineEditor::_delete_selected() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationNodeStateMachineEditor::_delete_all() {
|
void AnimationNodeStateMachineEditor::_delete_all() {
|
||||||
Vector<TransitionLine> multi_transitions = selected_multi_transition.multi_transitions;
|
|
||||||
selected_multi_transition = TransitionLine();
|
|
||||||
|
|
||||||
updating = true;
|
updating = true;
|
||||||
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
|
||||||
undo_redo->create_action("Transition(s) Removed");
|
undo_redo->create_action("Transition(s) Removed");
|
||||||
_erase_selected(true);
|
_erase_selected(true);
|
||||||
for (int i = 0; i < multi_transitions.size(); i++) {
|
|
||||||
selected_transition_from = multi_transitions[i].from_node;
|
|
||||||
selected_transition_to = multi_transitions[i].to_node;
|
|
||||||
_erase_selected(true);
|
|
||||||
}
|
|
||||||
undo_redo->commit_action();
|
undo_redo->commit_action();
|
||||||
updating = false;
|
updating = false;
|
||||||
|
|
||||||
|
@ -1120,14 +808,19 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
|
||||||
selected_transition_to = connecting_to_node;
|
selected_transition_to = connecting_to_node;
|
||||||
selected_transition_index = transition_lines.size();
|
selected_transition_index = transition_lines.size();
|
||||||
|
|
||||||
EditorNode::get_singleton()->push_item(tr.ptr(), "", true);
|
if (!state_machine->is_transition_across_group(selected_transition_index)) {
|
||||||
|
EditorNode::get_singleton()->push_item(tr.ptr(), "", true);
|
||||||
|
} else {
|
||||||
|
EditorNode::get_singleton()->push_item(tr.ptr(), "", true);
|
||||||
|
EditorNode::get_singleton()->push_item(nullptr, "", true);
|
||||||
|
}
|
||||||
_update_mode();
|
_update_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
connecting = false;
|
connecting = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, float p_fade_ratio, bool p_auto_advance, bool p_multi_transitions) {
|
void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, float p_fade_ratio, bool p_auto_advance, bool p_is_across_group) {
|
||||||
Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label"));
|
Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label"));
|
||||||
Color icon_color(1, 1, 1);
|
Color icon_color(1, 1, 1);
|
||||||
Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
|
Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
|
||||||
|
@ -1173,11 +866,7 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co
|
||||||
xf.columns[2] = (p_from + p_to) * 0.5 - xf.columns[1] * icon->get_height() * 0.5 - xf.columns[0] * icon->get_height() * 0.5;
|
xf.columns[2] = (p_from + p_to) * 0.5 - xf.columns[1] * icon->get_height() * 0.5 - xf.columns[0] * icon->get_height() * 0.5;
|
||||||
|
|
||||||
state_machine_draw->draw_set_transform_matrix(xf);
|
state_machine_draw->draw_set_transform_matrix(xf);
|
||||||
if (p_multi_transitions) {
|
if (!p_is_across_group) {
|
||||||
state_machine_draw->draw_texture(icons[0], Vector2(-icon->get_width(), 0), icon_color);
|
|
||||||
state_machine_draw->draw_texture(icons[0], Vector2(), icon_color);
|
|
||||||
state_machine_draw->draw_texture(icons[0], Vector2(icon->get_width(), 0), icon_color);
|
|
||||||
} else {
|
|
||||||
state_machine_draw->draw_texture(icon, Vector2(), icon_color);
|
state_machine_draw->draw_texture(icon, Vector2(), icon_color);
|
||||||
}
|
}
|
||||||
state_machine_draw->draw_set_transform_matrix(Transform2D());
|
state_machine_draw->draw_set_transform_matrix(Transform2D());
|
||||||
|
@ -1344,17 +1033,14 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
|
||||||
for (int i = 0; i < state_machine->get_transition_count(); i++) {
|
for (int i = 0; i < state_machine->get_transition_count(); i++) {
|
||||||
TransitionLine tl;
|
TransitionLine tl;
|
||||||
tl.transition_index = i;
|
tl.transition_index = i;
|
||||||
|
|
||||||
tl.from_node = state_machine->get_transition_from(i);
|
tl.from_node = state_machine->get_transition_from(i);
|
||||||
StringName local_from = String(tl.from_node).get_slicec('/', 0);
|
Vector2 ofs_from = (dragging_selected && selected_nodes.has(tl.from_node)) ? drag_ofs : Vector2();
|
||||||
local_from = local_from == ".." ? state_machine->start_node : local_from;
|
tl.from = (state_machine->get_node_position(tl.from_node) * EDSCALE) + ofs_from - state_machine->get_graph_offset() * EDSCALE;
|
||||||
Vector2 ofs_from = (dragging_selected && selected_nodes.has(local_from)) ? drag_ofs : Vector2();
|
|
||||||
tl.from = (state_machine->get_node_position(local_from) * EDSCALE) + ofs_from - state_machine->get_graph_offset() * EDSCALE;
|
|
||||||
|
|
||||||
tl.to_node = state_machine->get_transition_to(i);
|
tl.to_node = state_machine->get_transition_to(i);
|
||||||
StringName local_to = String(tl.to_node).get_slicec('/', 0);
|
Vector2 ofs_to = (dragging_selected && selected_nodes.has(tl.to_node)) ? drag_ofs : Vector2();
|
||||||
local_to = local_to == ".." ? state_machine->end_node : local_to;
|
tl.to = (state_machine->get_node_position(tl.to_node) * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE;
|
||||||
Vector2 ofs_to = (dragging_selected && selected_nodes.has(local_to)) ? drag_ofs : Vector2();
|
|
||||||
tl.to = (state_machine->get_node_position(local_to) * EDSCALE) + ofs_to - state_machine->get_graph_offset() * EDSCALE;
|
|
||||||
|
|
||||||
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i);
|
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(i);
|
||||||
tl.disabled = bool(tr->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED);
|
tl.disabled = bool(tr->get_advance_mode() == AnimationNodeStateMachineTransition::ADVANCE_MODE_DISABLED);
|
||||||
|
@ -1366,35 +1052,36 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
|
||||||
tl.travel = false;
|
tl.travel = false;
|
||||||
tl.fade_ratio = 0.0;
|
tl.fade_ratio = 0.0;
|
||||||
tl.hidden = false;
|
tl.hidden = false;
|
||||||
|
tl.is_across_group = state_machine->is_transition_across_group(i);
|
||||||
|
|
||||||
if (state_machine->has_local_transition(local_to, local_from)) { //offset if same exists
|
if (state_machine->has_transition(tl.to_node, tl.from_node)) { //offset if same exists
|
||||||
Vector2 offset = -(tl.from - tl.to).normalized().orthogonal() * tr_bidi_offset;
|
Vector2 offset = -(tl.from - tl.to).normalized().orthogonal() * tr_bidi_offset;
|
||||||
tl.from += offset;
|
tl.from += offset;
|
||||||
tl.to += offset;
|
tl.to += offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int j = 0; j < node_rects.size(); j++) {
|
for (int j = 0; j < node_rects.size(); j++) {
|
||||||
if (node_rects[j].node_name == local_from) {
|
if (node_rects[j].node_name == tl.from_node) {
|
||||||
_clip_src_line_to_rect(tl.from, tl.to, node_rects[j].node);
|
_clip_src_line_to_rect(tl.from, tl.to, node_rects[j].node);
|
||||||
}
|
}
|
||||||
if (node_rects[j].node_name == local_to) {
|
if (node_rects[j].node_name == tl.to_node) {
|
||||||
_clip_dst_line_to_rect(tl.from, tl.to, node_rects[j].node);
|
_clip_dst_line_to_rect(tl.from, tl.to, node_rects[j].node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tl.selected = selected_transition_from == tl.from_node && selected_transition_to == tl.to_node;
|
tl.selected = selected_transition_from == tl.from_node && selected_transition_to == tl.to_node;
|
||||||
|
|
||||||
if (blend_from == local_from && current == local_to) {
|
if (blend_from == tl.from_node && current == tl.to_node) {
|
||||||
tl.travel = true;
|
tl.travel = true;
|
||||||
tl.fade_ratio = MIN(1.0, fading_pos / fading_time);
|
tl.fade_ratio = MIN(1.0, fading_pos / fading_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (travel_path.size()) {
|
if (travel_path.size()) {
|
||||||
if (current == local_from && travel_path[0] == local_to) {
|
if (current == tl.from_node && travel_path[0] == tl.to_node) {
|
||||||
tl.travel = true;
|
tl.travel = true;
|
||||||
} else {
|
} else {
|
||||||
for (int j = 0; j < travel_path.size() - 1; j++) {
|
for (int j = 0; j < travel_path.size() - 1; j++) {
|
||||||
if (travel_path[j] == local_from && travel_path[j + 1] == local_to) {
|
if (travel_path[j] == tl.from_node && travel_path[j + 1] == tl.to_node) {
|
||||||
tl.travel = true;
|
tl.travel = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1408,17 +1095,11 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
|
||||||
tl.auto_advance = true;
|
tl.auto_advance = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if already have this local transition
|
// check if already have this transition
|
||||||
for (int j = 0; j < transition_lines.size(); j++) {
|
for (int j = 0; j < transition_lines.size(); j++) {
|
||||||
StringName from = String(transition_lines[j].from_node).get_slicec('/', 0);
|
if (transition_lines[j].from_node == tl.from_node && transition_lines[j].to_node == tl.to_node) {
|
||||||
StringName to = String(transition_lines[j].to_node).get_slicec('/', 0);
|
|
||||||
from = from == ".." ? state_machine->start_node : from;
|
|
||||||
to = to == ".." ? state_machine->end_node : to;
|
|
||||||
|
|
||||||
if (from == local_from && to == local_to) {
|
|
||||||
tl.hidden = true;
|
tl.hidden = true;
|
||||||
transition_lines.write[j].disabled = transition_lines[j].disabled && tl.disabled;
|
transition_lines.write[j].disabled = transition_lines[j].disabled && tl.disabled;
|
||||||
transition_lines.write[j].multi_transitions.push_back(tl);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transition_lines.push_back(tl);
|
transition_lines.push_back(tl);
|
||||||
|
@ -1427,7 +1108,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
|
||||||
for (int i = 0; i < transition_lines.size(); i++) {
|
for (int i = 0; i < transition_lines.size(); i++) {
|
||||||
TransitionLine tl = transition_lines[i];
|
TransitionLine tl = transition_lines[i];
|
||||||
if (!tl.hidden) {
|
if (!tl.hidden) {
|
||||||
_connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, tl.selected, tl.travel, tl.fade_ratio, tl.auto_advance, !tl.multi_transitions.is_empty());
|
_connection_draw(tl.from, tl.to, tl.mode, !tl.disabled, tl.selected, tl.travel, tl.fade_ratio, tl.auto_advance, tl.is_across_group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1481,6 +1162,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
|
||||||
state_machine_draw->draw_string(font, nr.name.position + Vector2(0, font->get_ascent(font_size)), name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
|
state_machine_draw->draw_string(font, nr.name.position + Vector2(0, font->get_ascent(font_size)), name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
|
||||||
offset.x += strsize + sep;
|
offset.x += strsize + sep;
|
||||||
|
|
||||||
|
nr.can_edit = needs_editor;
|
||||||
if (needs_editor) {
|
if (needs_editor) {
|
||||||
nr.edit.position = offset + Vector2(0, (h - edit->get_height()) / 2).floor();
|
nr.edit.position = offset + Vector2(0, (h - edit->get_height()) / 2).floor();
|
||||||
nr.edit.size = edit->get_size();
|
nr.edit.size = edit->get_size();
|
||||||
|
@ -1546,6 +1228,10 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(String
|
||||||
|
|
||||||
const NodeRect &nr = node_rects[idx];
|
const NodeRect &nr = node_rects[idx];
|
||||||
|
|
||||||
|
if (nr.can_edit) {
|
||||||
|
return; // It is not AnimationNodeAnimation.
|
||||||
|
}
|
||||||
|
|
||||||
Vector2 from;
|
Vector2 from;
|
||||||
from.x = nr.play.position.x;
|
from.x = nr.play.position.x;
|
||||||
from.y = (nr.play.position.y + nr.play.size.y + nr.node.position.y + nr.node.size.y) * 0.5;
|
from.y = (nr.play.position.y + nr.play.size.y + nr.node.position.y + nr.node.size.y) * 0.5;
|
||||||
|
@ -1584,14 +1270,14 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw_all() {
|
||||||
{
|
{
|
||||||
float len = MAX(0.0001, current_length);
|
float len = MAX(0.0001, current_length);
|
||||||
float pos = CLAMP(current_play_pos, 0, len);
|
float pos = CLAMP(current_play_pos, 0, len);
|
||||||
float c = pos / len;
|
float c = current_length == HUGE_LENGTH ? 1 : (pos / len);
|
||||||
_state_machine_pos_draw_individual(playback->get_current_node(), c);
|
_state_machine_pos_draw_individual(playback->get_current_node(), c);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
float len = MAX(0.0001, fade_from_length);
|
float len = MAX(0.0001, fade_from_length);
|
||||||
float pos = CLAMP(fade_from_current_play_pos, 0, len);
|
float pos = CLAMP(fade_from_current_play_pos, 0, len);
|
||||||
float c = pos / len;
|
float c = fade_from_length == HUGE_LENGTH ? 1 : (pos / len);
|
||||||
_state_machine_pos_draw_individual(playback->get_fading_from_node(), c);
|
_state_machine_pos_draw_individual(playback->get_fading_from_node(), c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1630,8 +1316,6 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
|
||||||
auto_advance->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons")));
|
auto_advance->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons")));
|
||||||
|
|
||||||
tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
|
tool_erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
|
||||||
tool_group->set_icon(get_theme_icon(SNAME("Group"), SNAME("EditorIcons")));
|
|
||||||
tool_ungroup->set_icon(get_theme_icon(SNAME("Ungroup"), SNAME("EditorIcons")));
|
|
||||||
|
|
||||||
play_mode->clear();
|
play_mode->clear();
|
||||||
play_mode->add_icon_item(get_theme_icon(SNAME("PlayTravel"), SNAME("EditorIcons")), TTR("Travel"));
|
play_mode->add_icon_item(get_theme_icon(SNAME("PlayTravel"), SNAME("EditorIcons")), TTR("Travel"));
|
||||||
|
@ -1655,10 +1339,6 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
|
||||||
error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
|
error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails.");
|
||||||
} else if (tree->is_state_invalid()) {
|
} else if (tree->is_state_invalid()) {
|
||||||
error = tree->get_invalid_state_reason();
|
error = tree->get_invalid_state_reason();
|
||||||
/*} else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) {
|
|
||||||
if (state_machine->get_start_node() == StringName() || state_machine->get_end_node() == StringName()) {
|
|
||||||
error = TTR("Start and end nodes are needed for a sub-transition.");
|
|
||||||
}*/
|
|
||||||
} else if (playback.is_null()) {
|
} else if (playback.is_null()) {
|
||||||
error = vformat(TTR("No playback resource set at path: %s."), AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
|
error = vformat(TTR("No playback resource set at path: %s."), AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
|
||||||
}
|
}
|
||||||
|
@ -1780,8 +1460,12 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
|
||||||
|
|
||||||
while (anodesm.is_valid()) {
|
while (anodesm.is_valid()) {
|
||||||
current_node_playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + next + "/playback");
|
current_node_playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + next + "/playback");
|
||||||
next += "/" + current_node_playback->get_current_node();
|
StringName cnode = current_node_playback->get_current_node();
|
||||||
anodesm = anodesm->get_node(current_node_playback->get_current_node());
|
next += "/" + cnode;
|
||||||
|
if (!anodesm->has_node(cnode)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
anodesm = anodesm->get_node(cnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// when current_node is a state machine, use playback of current_node to set play_pos
|
// when current_node is a state machine, use playback of current_node to set play_pos
|
||||||
|
@ -1883,10 +1567,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
|
||||||
for (int j = 0; j < state_machine->get_transition_count(); j++) {
|
for (int j = 0; j < state_machine->get_transition_count(); j++) {
|
||||||
String from = state_machine->get_transition_from(j);
|
String from = state_machine->get_transition_from(j);
|
||||||
String to = state_machine->get_transition_to(j);
|
String to = state_machine->get_transition_to(j);
|
||||||
String local_from = from.get_slicec('/', 0);
|
if (from == node_rects[i].node_name || to == node_rects[i].node_name) {
|
||||||
String local_to = to.get_slicec('/', 0);
|
|
||||||
|
|
||||||
if (local_from == node_rects[i].node_name || local_to == node_rects[i].node_name) {
|
|
||||||
undo_redo->add_undo_method(state_machine.ptr(), "add_transition", from, to, state_machine->get_transition(j));
|
undo_redo->add_undo_method(state_machine.ptr(), "add_transition", from, to, state_machine->get_transition(j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1903,30 +1584,6 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
|
||||||
selected_nodes.clear();
|
selected_nodes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!selected_multi_transition.multi_transitions.is_empty()) {
|
|
||||||
delete_tree->clear();
|
|
||||||
|
|
||||||
TreeItem *root = delete_tree->create_item();
|
|
||||||
|
|
||||||
TreeItem *item = delete_tree->create_item(root);
|
|
||||||
item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
|
|
||||||
item->set_text(0, String(selected_transition_from) + " -> " + selected_transition_to);
|
|
||||||
item->set_editable(0, true);
|
|
||||||
|
|
||||||
for (int i = 0; i < selected_multi_transition.multi_transitions.size(); i++) {
|
|
||||||
String from = selected_multi_transition.multi_transitions[i].from_node;
|
|
||||||
String to = selected_multi_transition.multi_transitions[i].to_node;
|
|
||||||
|
|
||||||
item = delete_tree->create_item(root);
|
|
||||||
item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
|
|
||||||
item->set_text(0, from + " -> " + to);
|
|
||||||
item->set_editable(0, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete_window->popup_centered(Vector2(400, 200));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selected_transition_to != StringName() && selected_transition_from != StringName() && state_machine->has_transition(selected_transition_from, selected_transition_to)) {
|
if (selected_transition_to != StringName() && selected_transition_from != StringName() && state_machine->has_transition(selected_transition_from, selected_transition_to)) {
|
||||||
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(state_machine->find_transition(selected_transition_from, selected_transition_to));
|
Ref<AnimationNodeStateMachineTransition> tr = state_machine->get_transition(state_machine->find_transition(selected_transition_from, selected_transition_to));
|
||||||
if (!p_nested_action) {
|
if (!p_nested_action) {
|
||||||
|
@ -1945,7 +1602,6 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
|
||||||
selected_transition_from = StringName();
|
selected_transition_from = StringName();
|
||||||
selected_transition_to = StringName();
|
selected_transition_to = StringName();
|
||||||
selected_transition_index = -1;
|
selected_transition_index = -1;
|
||||||
selected_multi_transition = TransitionLine();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state_machine_draw->queue_redraw();
|
state_machine_draw->queue_redraw();
|
||||||
|
@ -1957,24 +1613,6 @@ void AnimationNodeStateMachineEditor::_update_mode() {
|
||||||
bool nothing_selected = selected_nodes.is_empty() && selected_transition_from == StringName() && selected_transition_to == StringName();
|
bool nothing_selected = selected_nodes.is_empty() && selected_transition_from == StringName() && selected_transition_to == StringName();
|
||||||
bool start_end_selected = selected_nodes.size() == 1 && (*selected_nodes.begin() == state_machine->start_node || *selected_nodes.begin() == state_machine->end_node);
|
bool start_end_selected = selected_nodes.size() == 1 && (*selected_nodes.begin() == state_machine->start_node || *selected_nodes.begin() == state_machine->end_node);
|
||||||
tool_erase->set_disabled(nothing_selected || start_end_selected || read_only);
|
tool_erase->set_disabled(nothing_selected || start_end_selected || read_only);
|
||||||
|
|
||||||
if (selected_nodes.is_empty() || start_end_selected || read_only) {
|
|
||||||
tool_group->set_disabled(true);
|
|
||||||
tool_group->set_visible(true);
|
|
||||||
tool_ungroup->set_visible(false);
|
|
||||||
} else {
|
|
||||||
Ref<AnimationNodeStateMachine> ansm = state_machine->get_node(*selected_nodes.begin());
|
|
||||||
|
|
||||||
if (selected_nodes.size() == 1 && ansm.is_valid()) {
|
|
||||||
tool_group->set_disabled(true);
|
|
||||||
tool_group->set_visible(false);
|
|
||||||
tool_ungroup->set_visible(true);
|
|
||||||
} else {
|
|
||||||
tool_group->set_disabled(false);
|
|
||||||
tool_group->set_visible(true);
|
|
||||||
tool_ungroup->set_visible(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
selection_tools_hb->hide();
|
selection_tools_hb->hide();
|
||||||
}
|
}
|
||||||
|
@ -2037,20 +1675,6 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
|
||||||
top_hb->add_child(selection_tools_hb);
|
top_hb->add_child(selection_tools_hb);
|
||||||
selection_tools_hb->add_child(memnew(VSeparator));
|
selection_tools_hb->add_child(memnew(VSeparator));
|
||||||
|
|
||||||
tool_group = memnew(Button);
|
|
||||||
tool_group->set_flat(true);
|
|
||||||
tool_group->set_tooltip_text(TTR("Group Selected Node(s)") + " (Ctrl+G)");
|
|
||||||
tool_group->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_group_selected_nodes));
|
|
||||||
tool_group->set_disabled(true);
|
|
||||||
selection_tools_hb->add_child(tool_group);
|
|
||||||
|
|
||||||
tool_ungroup = memnew(Button);
|
|
||||||
tool_ungroup->set_flat(true);
|
|
||||||
tool_ungroup->set_tooltip_text(TTR("Ungroup Selected Node") + " (Ctrl+Shift+G)");
|
|
||||||
tool_ungroup->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_ungroup_selected_nodes));
|
|
||||||
tool_ungroup->set_visible(false);
|
|
||||||
selection_tools_hb->add_child(tool_ungroup);
|
|
||||||
|
|
||||||
tool_erase = memnew(Button);
|
tool_erase = memnew(Button);
|
||||||
tool_erase->set_flat(true);
|
tool_erase->set_flat(true);
|
||||||
tool_erase->set_tooltip_text(TTR("Remove selected node or transition."));
|
tool_erase->set_tooltip_text(TTR("Remove selected node or transition."));
|
||||||
|
|
|
@ -56,8 +56,6 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
|
||||||
LineEdit *name_edit = nullptr;
|
LineEdit *name_edit = nullptr;
|
||||||
|
|
||||||
HBoxContainer *selection_tools_hb = nullptr;
|
HBoxContainer *selection_tools_hb = nullptr;
|
||||||
Button *tool_group = nullptr;
|
|
||||||
Button *tool_ungroup = nullptr;
|
|
||||||
Button *tool_erase = nullptr;
|
Button *tool_erase = nullptr;
|
||||||
|
|
||||||
HBoxContainer *transition_tools_hb = nullptr;
|
HBoxContainer *transition_tools_hb = nullptr;
|
||||||
|
@ -85,7 +83,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
|
||||||
static AnimationNodeStateMachineEditor *singleton;
|
static AnimationNodeStateMachineEditor *singleton;
|
||||||
|
|
||||||
void _state_machine_gui_input(const Ref<InputEvent> &p_event);
|
void _state_machine_gui_input(const Ref<InputEvent> &p_event);
|
||||||
void _connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, float p_fade_ratio, bool p_auto_advance, bool p_multi_transitions);
|
void _connection_draw(const Vector2 &p_from, const Vector2 &p_to, AnimationNodeStateMachineTransition::SwitchMode p_mode, bool p_enabled, bool p_selected, bool p_travel, float p_fade_ratio, bool p_auto_advance, bool p_is_across_group);
|
||||||
|
|
||||||
void _state_machine_draw();
|
void _state_machine_draw();
|
||||||
|
|
||||||
|
@ -136,6 +134,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
|
||||||
Rect2 play;
|
Rect2 play;
|
||||||
Rect2 name;
|
Rect2 name;
|
||||||
Rect2 edit;
|
Rect2 edit;
|
||||||
|
bool can_edit;
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector<NodeRect> node_rects;
|
Vector<NodeRect> node_rects;
|
||||||
|
@ -156,7 +155,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
|
||||||
float fade_ratio;
|
float fade_ratio;
|
||||||
bool hidden;
|
bool hidden;
|
||||||
int transition_index;
|
int transition_index;
|
||||||
Vector<TransitionLine> multi_transitions;
|
bool is_across_group = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector<TransitionLine> transition_lines;
|
Vector<TransitionLine> transition_lines;
|
||||||
|
@ -178,7 +177,6 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
|
||||||
StringName selected_transition_from;
|
StringName selected_transition_from;
|
||||||
StringName selected_transition_to;
|
StringName selected_transition_to;
|
||||||
int selected_transition_index;
|
int selected_transition_index;
|
||||||
TransitionLine selected_multi_transition;
|
|
||||||
void _add_transition(const bool p_nested_action = false);
|
void _add_transition(const bool p_nested_action = false);
|
||||||
|
|
||||||
StringName over_node;
|
StringName over_node;
|
||||||
|
@ -190,19 +188,17 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
|
||||||
void _open_editor(const String &p_name);
|
void _open_editor(const String &p_name);
|
||||||
void _scroll_changed(double);
|
void _scroll_changed(double);
|
||||||
|
|
||||||
|
String _get_root_playback_path(String &r_node_directory);
|
||||||
|
|
||||||
void _clip_src_line_to_rect(Vector2 &r_from, const Vector2 &p_to, const Rect2 &p_rect);
|
void _clip_src_line_to_rect(Vector2 &r_from, const Vector2 &p_to, const Rect2 &p_rect);
|
||||||
void _clip_dst_line_to_rect(const Vector2 &p_from, Vector2 &r_to, const Rect2 &p_rect);
|
void _clip_dst_line_to_rect(const Vector2 &p_from, Vector2 &r_to, const Rect2 &p_rect);
|
||||||
|
|
||||||
void _erase_selected(const bool p_nested_action = false);
|
void _erase_selected(const bool p_nested_action = false);
|
||||||
void _update_mode();
|
void _update_mode();
|
||||||
void _open_menu(const Vector2 &p_position);
|
void _open_menu(const Vector2 &p_position);
|
||||||
void _open_connect_menu(const Vector2 &p_position);
|
bool _create_submenu(PopupMenu *p_menu, Ref<AnimationNodeStateMachine> p_nodesm, const StringName &p_name, const StringName &p_path);
|
||||||
bool _create_submenu(PopupMenu *p_menu, Ref<AnimationNodeStateMachine> p_nodesm, const StringName &p_name, const StringName &p_path, bool from_root = false, Vector<Ref<AnimationNodeStateMachine>> p_parents = Vector<Ref<AnimationNodeStateMachine>>());
|
|
||||||
void _stop_connecting();
|
void _stop_connecting();
|
||||||
|
|
||||||
void _group_selected_nodes();
|
|
||||||
void _ungroup_selected_nodes();
|
|
||||||
|
|
||||||
void _delete_selected();
|
void _delete_selected();
|
||||||
void _delete_all();
|
void _delete_all();
|
||||||
void _delete_tree_draw();
|
void _delete_tree_draw();
|
||||||
|
|
|
@ -66,11 +66,6 @@ void AnimationTreeEditor::edit(AnimationTree *p_tree) {
|
||||||
|
|
||||||
Vector<String> path;
|
Vector<String> path;
|
||||||
if (tree) {
|
if (tree) {
|
||||||
if (tree->has_meta("_tree_edit_path")) {
|
|
||||||
path = tree->get_meta("_tree_edit_path");
|
|
||||||
} else {
|
|
||||||
current_root = ObjectID();
|
|
||||||
}
|
|
||||||
edit_path(path);
|
edit_path(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) {
|
Ref<AnimationNode> AnimationNodeBlendSpace1D::get_child_by_name(const StringName &p_name) const {
|
||||||
return get_blend_point_node(p_name.operator String().to_int());
|
return get_blend_point_node(p_name.operator String().to_int());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,14 +272,14 @@ void AnimationNodeBlendSpace1D::_add_blend_point(int p_index, const Ref<Animatio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeBlendSpace1D::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
if (blend_points_used == 0) {
|
if (blend_points_used == 0) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blend_points_used == 1) {
|
if (blend_points_used == 1) {
|
||||||
// only one point available, just play that animation
|
// only one point available, just play that animation
|
||||||
return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
return blend_node(blend_points[0].name, blend_points[0].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
double blend_pos = get_parameter(blend_position);
|
double blend_pos = get_parameter(blend_position);
|
||||||
|
@ -351,10 +351,10 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_is_
|
||||||
|
|
||||||
for (int i = 0; i < blend_points_used; i++) {
|
for (int i = 0; i < blend_points_used; i++) {
|
||||||
if (i == point_lower || i == point_higher) {
|
if (i == point_lower || i == point_higher) {
|
||||||
double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true);
|
double remaining = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, weights[i], FILTER_IGNORE, true, p_test_only);
|
||||||
max_time_remaining = MAX(max_time_remaining, remaining);
|
max_time_remaining = MAX(max_time_remaining, remaining);
|
||||||
} else if (sync) {
|
} else if (sync) {
|
||||||
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -379,22 +379,22 @@ double AnimationNodeBlendSpace1D::process(double p_time, bool p_seek, bool p_is_
|
||||||
na_n->set_backward(na_c->is_backward());
|
na_n->set_backward(na_c->is_backward());
|
||||||
}
|
}
|
||||||
//see how much animation remains
|
//see how much animation remains
|
||||||
from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_is_external_seeking, 0.0, FILTER_IGNORE, true);
|
from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_is_external_seeking, 0.0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
max_time_remaining = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
max_time_remaining = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
cur_length_internal = from + max_time_remaining;
|
cur_length_internal = from + max_time_remaining;
|
||||||
|
|
||||||
cur_closest = new_closest;
|
cur_closest = new_closest;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
max_time_remaining = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
max_time_remaining = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sync) {
|
if (sync) {
|
||||||
for (int i = 0; i < blend_points_used; i++) {
|
for (int i = 0; i < blend_points_used; i++) {
|
||||||
if (i != cur_closest) {
|
if (i != cur_closest) {
|
||||||
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,10 +114,10 @@ public:
|
||||||
void set_use_sync(bool p_sync);
|
void set_use_sync(bool p_sync);
|
||||||
bool is_using_sync() const;
|
bool is_using_sync() const;
|
||||||
|
|
||||||
double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
String get_caption() const override;
|
String get_caption() const override;
|
||||||
|
|
||||||
Ref<AnimationNode> get_child_by_name(const StringName &p_name) override;
|
Ref<AnimationNode> get_child_by_name(const StringName &p_name) const override;
|
||||||
|
|
||||||
AnimationNodeBlendSpace1D();
|
AnimationNodeBlendSpace1D();
|
||||||
~AnimationNodeBlendSpace1D();
|
~AnimationNodeBlendSpace1D();
|
||||||
|
|
|
@ -442,7 +442,7 @@ void AnimationNodeBlendSpace2D::_blend_triangle(const Vector2 &p_pos, const Vect
|
||||||
r_weights[2] = w;
|
r_weights[2] = w;
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeBlendSpace2D::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
_update_triangles();
|
_update_triangles();
|
||||||
|
|
||||||
Vector2 blend_pos = get_parameter(blend_position);
|
Vector2 blend_pos = get_parameter(blend_position);
|
||||||
|
@ -512,7 +512,7 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_is_
|
||||||
for (int j = 0; j < 3; j++) {
|
for (int j = 0; j < 3; j++) {
|
||||||
if (i == triangle_points[j]) {
|
if (i == triangle_points[j]) {
|
||||||
//blend with the given weight
|
//blend with the given weight
|
||||||
double t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, blend_weights[j], FILTER_IGNORE, true);
|
double t = blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, blend_weights[j], FILTER_IGNORE, true, p_test_only);
|
||||||
if (first || t < mind) {
|
if (first || t < mind) {
|
||||||
mind = t;
|
mind = t;
|
||||||
first = false;
|
first = false;
|
||||||
|
@ -523,7 +523,7 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_is_
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sync && !found) {
|
if (sync && !found) {
|
||||||
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -548,22 +548,22 @@ double AnimationNodeBlendSpace2D::process(double p_time, bool p_seek, bool p_is_
|
||||||
na_n->set_backward(na_c->is_backward());
|
na_n->set_backward(na_c->is_backward());
|
||||||
}
|
}
|
||||||
//see how much animation remains
|
//see how much animation remains
|
||||||
from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_is_external_seeking, 0.0, FILTER_IGNORE, true);
|
from = cur_length_internal - blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, false, p_is_external_seeking, 0.0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
mind = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
mind = blend_node(blend_points[new_closest].name, blend_points[new_closest].node, from, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
cur_length_internal = from + mind;
|
cur_length_internal = from + mind;
|
||||||
|
|
||||||
cur_closest = new_closest;
|
cur_closest = new_closest;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
mind = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
mind = blend_node(blend_points[cur_closest].name, blend_points[cur_closest].node, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sync) {
|
if (sync) {
|
||||||
for (int i = 0; i < blend_points_used; i++) {
|
for (int i = 0; i < blend_points_used; i++) {
|
||||||
if (i != cur_closest) {
|
if (i != cur_closest) {
|
||||||
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
blend_node(blend_points[i].name, blend_points[i].node, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -604,7 +604,7 @@ bool AnimationNodeBlendSpace2D::get_auto_triangles() const {
|
||||||
return auto_triangles;
|
return auto_triangles;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<AnimationNode> AnimationNodeBlendSpace2D::get_child_by_name(const StringName &p_name) {
|
Ref<AnimationNode> AnimationNodeBlendSpace2D::get_child_by_name(const StringName &p_name) const {
|
||||||
return get_blend_point_node(p_name.operator String().to_int());
|
return get_blend_point_node(p_name.operator String().to_int());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ public:
|
||||||
void set_y_label(const String &p_label);
|
void set_y_label(const String &p_label);
|
||||||
String get_y_label() const;
|
String get_y_label() const;
|
||||||
|
|
||||||
virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
|
|
||||||
Vector2 get_closest_point(const Vector2 &p_point);
|
Vector2 get_closest_point(const Vector2 &p_point);
|
||||||
|
@ -143,7 +143,7 @@ public:
|
||||||
void set_use_sync(bool p_sync);
|
void set_use_sync(bool p_sync);
|
||||||
bool is_using_sync() const;
|
bool is_using_sync() const;
|
||||||
|
|
||||||
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) override;
|
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) const override;
|
||||||
|
|
||||||
AnimationNodeBlendSpace2D();
|
AnimationNodeBlendSpace2D();
|
||||||
~AnimationNodeBlendSpace2D();
|
~AnimationNodeBlendSpace2D();
|
||||||
|
|
|
@ -64,7 +64,7 @@ void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeAnimation::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
AnimationPlayer *ap = state->player;
|
AnimationPlayer *ap = state->player;
|
||||||
ERR_FAIL_COND_V(!ap, 0);
|
ERR_FAIL_COND_V(!ap, 0);
|
||||||
|
|
||||||
|
@ -99,6 +99,7 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_ext
|
||||||
step = p_time;
|
step = p_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_looping = false;
|
||||||
if (anim->get_loop_mode() == Animation::LOOP_PINGPONG) {
|
if (anim->get_loop_mode() == Animation::LOOP_PINGPONG) {
|
||||||
if (!Math::is_zero_approx(anim_size)) {
|
if (!Math::is_zero_approx(anim_size)) {
|
||||||
if (prev_time >= 0 && cur_time < 0) {
|
if (prev_time >= 0 && cur_time < 0) {
|
||||||
|
@ -111,6 +112,7 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_ext
|
||||||
}
|
}
|
||||||
cur_time = Math::pingpong(cur_time, anim_size);
|
cur_time = Math::pingpong(cur_time, anim_size);
|
||||||
}
|
}
|
||||||
|
is_looping = true;
|
||||||
} else if (anim->get_loop_mode() == Animation::LOOP_LINEAR) {
|
} else if (anim->get_loop_mode() == Animation::LOOP_LINEAR) {
|
||||||
if (!Math::is_zero_approx(anim_size)) {
|
if (!Math::is_zero_approx(anim_size)) {
|
||||||
if (prev_time >= 0 && cur_time < 0) {
|
if (prev_time >= 0 && cur_time < 0) {
|
||||||
|
@ -122,6 +124,7 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_ext
|
||||||
cur_time = Math::fposmod(cur_time, anim_size);
|
cur_time = Math::fposmod(cur_time, anim_size);
|
||||||
}
|
}
|
||||||
backward = false;
|
backward = false;
|
||||||
|
is_looping = true;
|
||||||
} else {
|
} else {
|
||||||
if (cur_time < 0) {
|
if (cur_time < 0) {
|
||||||
step += cur_time;
|
step += cur_time;
|
||||||
|
@ -159,14 +162,16 @@ double AnimationNodeAnimation::process(double p_time, bool p_seek, bool p_is_ext
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (play_mode == PLAY_MODE_FORWARD) {
|
if (!p_test_only) {
|
||||||
blend_animation(animation, cur_time, step, p_seek, p_is_external_seeking, 1.0, looped_flag);
|
if (play_mode == PLAY_MODE_FORWARD) {
|
||||||
} else {
|
blend_animation(animation, cur_time, step, p_seek, p_is_external_seeking, 1.0, looped_flag);
|
||||||
blend_animation(animation, anim_size - cur_time, -step, p_seek, p_is_external_seeking, 1.0, looped_flag);
|
} else {
|
||||||
|
blend_animation(animation, anim_size - cur_time, -step, p_seek, p_is_external_seeking, 1.0, looped_flag);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
set_parameter(time, cur_time);
|
set_parameter(time, cur_time);
|
||||||
|
|
||||||
return anim_size - cur_time;
|
return is_looping ? HUGE_LENGTH : anim_size - cur_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
String AnimationNodeAnimation::get_caption() const {
|
String AnimationNodeAnimation::get_caption() const {
|
||||||
|
@ -311,7 +316,7 @@ bool AnimationNodeOneShot::has_filter() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeOneShot::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
OneShotRequest cur_request = static_cast<OneShotRequest>((int)get_parameter(request));
|
OneShotRequest cur_request = static_cast<OneShotRequest>((int)get_parameter(request));
|
||||||
bool cur_active = get_parameter(active);
|
bool cur_active = get_parameter(active);
|
||||||
double cur_time = get_parameter(time);
|
double cur_time = get_parameter(time);
|
||||||
|
@ -324,7 +329,7 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_exter
|
||||||
if (cur_request == ONE_SHOT_REQUEST_ABORT) {
|
if (cur_request == ONE_SHOT_REQUEST_ABORT) {
|
||||||
set_parameter(active, false);
|
set_parameter(active, false);
|
||||||
set_parameter(time_to_restart, -1);
|
set_parameter(time_to_restart, -1);
|
||||||
return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
|
return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync, p_test_only);
|
||||||
} else if (!do_start && !cur_active) {
|
} else if (!do_start && !cur_active) {
|
||||||
if (cur_time_to_restart >= 0.0 && !p_seek) {
|
if (cur_time_to_restart >= 0.0 && !p_seek) {
|
||||||
cur_time_to_restart -= p_time;
|
cur_time_to_restart -= p_time;
|
||||||
|
@ -334,7 +339,7 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_exter
|
||||||
set_parameter(time_to_restart, cur_time_to_restart);
|
set_parameter(time_to_restart, cur_time_to_restart);
|
||||||
}
|
}
|
||||||
if (!do_start) {
|
if (!do_start) {
|
||||||
return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
|
return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync, p_test_only);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,11 +375,11 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_exter
|
||||||
|
|
||||||
double main_rem = 0.0;
|
double main_rem = 0.0;
|
||||||
if (mix == MIX_MODE_ADD) {
|
if (mix == MIX_MODE_ADD) {
|
||||||
main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
|
main_rem = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync, p_test_only);
|
||||||
} else {
|
} else {
|
||||||
main_rem = blend_input(0, p_time, use_blend && p_seek, p_is_external_seeking, 1.0 - blend, FILTER_BLEND, sync); // Unlike below, processing this edge is a corner case.
|
main_rem = blend_input(0, p_time, use_blend && p_seek, p_is_external_seeking, 1.0 - blend, FILTER_BLEND, sync, p_test_only); // Unlike below, processing this edge is a corner case.
|
||||||
}
|
}
|
||||||
double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_PASS, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
double os_rem = blend_input(1, os_seek ? cur_time : p_time, os_seek, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_PASS, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
||||||
|
|
||||||
if (do_start) {
|
if (do_start) {
|
||||||
cur_remaining = os_rem;
|
cur_remaining = os_rem;
|
||||||
|
@ -459,10 +464,10 @@ bool AnimationNodeAdd2::has_filter() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeAdd2::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeAdd2::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
double amount = get_parameter(add_amount);
|
double amount = get_parameter(add_amount);
|
||||||
double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
|
double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync, p_test_only);
|
||||||
blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync);
|
blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync, p_test_only);
|
||||||
|
|
||||||
return rem0;
|
return rem0;
|
||||||
}
|
}
|
||||||
|
@ -493,11 +498,11 @@ bool AnimationNodeAdd3::has_filter() const {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeAdd3::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeAdd3::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
double amount = get_parameter(add_amount);
|
double amount = get_parameter(add_amount);
|
||||||
blend_input(0, p_time, p_seek, p_is_external_seeking, MAX(0, -amount), FILTER_PASS, sync);
|
blend_input(0, p_time, p_seek, p_is_external_seeking, MAX(0, -amount), FILTER_PASS, sync, p_test_only);
|
||||||
double rem0 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
|
double rem0 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync, p_test_only);
|
||||||
blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_PASS, sync);
|
blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_PASS, sync, p_test_only);
|
||||||
|
|
||||||
return rem0;
|
return rem0;
|
||||||
}
|
}
|
||||||
|
@ -525,11 +530,11 @@ String AnimationNodeBlend2::get_caption() const {
|
||||||
return "Blend2";
|
return "Blend2";
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeBlend2::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeBlend2::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
double amount = get_parameter(blend_amount);
|
double amount = get_parameter(blend_amount);
|
||||||
|
|
||||||
double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - amount, FILTER_BLEND, sync);
|
double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0 - amount, FILTER_BLEND, sync, p_test_only);
|
||||||
double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync);
|
double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, amount, FILTER_PASS, sync, p_test_only);
|
||||||
|
|
||||||
return amount > 0.5 ? rem1 : rem0; // Hacky but good enough.
|
return amount > 0.5 ? rem1 : rem0; // Hacky but good enough.
|
||||||
}
|
}
|
||||||
|
@ -560,11 +565,11 @@ String AnimationNodeBlend3::get_caption() const {
|
||||||
return "Blend3";
|
return "Blend3";
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeBlend3::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeBlend3::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
double amount = get_parameter(blend_amount);
|
double amount = get_parameter(blend_amount);
|
||||||
double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, MAX(0, -amount), FILTER_IGNORE, sync);
|
double rem0 = blend_input(0, p_time, p_seek, p_is_external_seeking, MAX(0, -amount), FILTER_IGNORE, sync, p_test_only);
|
||||||
double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0 - ABS(amount), FILTER_IGNORE, sync);
|
double rem1 = blend_input(1, p_time, p_seek, p_is_external_seeking, 1.0 - ABS(amount), FILTER_IGNORE, sync, p_test_only);
|
||||||
double rem2 = blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_IGNORE, sync);
|
double rem2 = blend_input(2, p_time, p_seek, p_is_external_seeking, MAX(0, amount), FILTER_IGNORE, sync, p_test_only);
|
||||||
|
|
||||||
return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); // Hacky but good enough.
|
return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); // Hacky but good enough.
|
||||||
}
|
}
|
||||||
|
@ -592,12 +597,12 @@ String AnimationNodeTimeScale::get_caption() const {
|
||||||
return "TimeScale";
|
return "TimeScale";
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeTimeScale::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeTimeScale::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
double cur_scale = get_parameter(scale);
|
double cur_scale = get_parameter(scale);
|
||||||
if (p_seek) {
|
if (p_seek) {
|
||||||
return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
} else {
|
} else {
|
||||||
return blend_input(0, p_time * cur_scale, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
return blend_input(0, p_time * cur_scale, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,16 +627,16 @@ String AnimationNodeTimeSeek::get_caption() const {
|
||||||
return "TimeSeek";
|
return "TimeSeek";
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeTimeSeek::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeTimeSeek::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
double cur_seek_pos = get_parameter(seek_pos_request);
|
double cur_seek_pos = get_parameter(seek_pos_request);
|
||||||
if (p_seek) {
|
if (p_seek) {
|
||||||
return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
return blend_input(0, p_time, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
} else if (cur_seek_pos >= 0) {
|
} else if (cur_seek_pos >= 0) {
|
||||||
double ret = blend_input(0, cur_seek_pos, true, true, 1.0, FILTER_IGNORE, true);
|
double ret = blend_input(0, cur_seek_pos, true, true, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
set_parameter(seek_pos_request, -1.0); // Reset.
|
set_parameter(seek_pos_request, -1.0); // Reset.
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
return blend_input(0, p_time, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
return blend_input(0, p_time, false, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -815,7 +820,7 @@ bool AnimationNodeTransition::is_allow_transition_to_self() const {
|
||||||
return allow_transition_to_self;
|
return allow_transition_to_self;
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeTransition::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
String cur_transition_request = get_parameter(transition_request);
|
String cur_transition_request = get_parameter(transition_request);
|
||||||
int cur_current_index = get_parameter(current_index);
|
int cur_current_index = get_parameter(current_index);
|
||||||
int cur_prev_index = get_parameter(prev_index);
|
int cur_prev_index = get_parameter(prev_index);
|
||||||
|
@ -881,7 +886,7 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
|
||||||
// Special case for restart.
|
// Special case for restart.
|
||||||
if (restart) {
|
if (restart) {
|
||||||
set_parameter(time, 0);
|
set_parameter(time, 0);
|
||||||
return blend_input(cur_current_index, 0, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
return blend_input(cur_current_index, 0, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switched) {
|
if (switched) {
|
||||||
|
@ -898,14 +903,14 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
|
||||||
if (sync) {
|
if (sync) {
|
||||||
for (int i = 0; i < get_input_count(); i++) {
|
for (int i = 0; i < get_input_count(); i++) {
|
||||||
if (i != cur_current_index && i != cur_prev_index) {
|
if (i != cur_current_index && i != cur_prev_index) {
|
||||||
blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
|
blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur_prev_index < 0) { // Process current animation, check for transition.
|
if (cur_prev_index < 0) { // Process current animation, check for transition.
|
||||||
|
|
||||||
rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
|
|
||||||
if (p_seek) {
|
if (p_seek) {
|
||||||
cur_time = p_time;
|
cur_time = p_time;
|
||||||
|
@ -935,12 +940,12 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
|
||||||
|
|
||||||
// Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
// Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
||||||
if (input_data[cur_current_index].reset && !p_seek && switched) { // Just switched, seek to start of current.
|
if (input_data[cur_current_index].reset && !p_seek && switched) { // Just switched, seek to start of current.
|
||||||
rem = blend_input(cur_current_index, 0, true, p_is_external_seeking, blend_inv, FILTER_IGNORE, true);
|
rem = blend_input(cur_current_index, 0, true, p_is_external_seeking, blend_inv, FILTER_IGNORE, true, p_test_only);
|
||||||
} else {
|
} else {
|
||||||
rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, blend_inv, FILTER_IGNORE, true);
|
rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, blend_inv, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
blend_input(cur_prev_index, p_time, use_blend && p_seek, p_is_external_seeking, blend, FILTER_IGNORE, true);
|
blend_input(cur_prev_index, p_time, use_blend && p_seek, p_is_external_seeking, blend, FILTER_IGNORE, true, p_test_only);
|
||||||
if (p_seek) {
|
if (p_seek) {
|
||||||
cur_time = p_time;
|
cur_time = p_time;
|
||||||
} else {
|
} else {
|
||||||
|
@ -999,8 +1004,8 @@ String AnimationNodeOutput::get_caption() const {
|
||||||
return "Output";
|
return "Output";
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeOutput::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeOutput::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true, p_test_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimationNodeOutput::AnimationNodeOutput() {
|
AnimationNodeOutput::AnimationNodeOutput() {
|
||||||
|
@ -1218,9 +1223,9 @@ String AnimationNodeBlendTree::get_caption() const {
|
||||||
return "BlendTree";
|
return "BlendTree";
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNodeBlendTree::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNodeBlendTree::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
|
Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node;
|
||||||
return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
|
return _blend_node("output", nodes[SceneStringNames::get_singleton()->output].connections, this, output, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true, nullptr, p_test_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {
|
void AnimationNodeBlendTree::get_node_list(List<StringName> *r_list) {
|
||||||
|
@ -1237,7 +1242,7 @@ Vector2 AnimationNodeBlendTree::get_graph_offset() const {
|
||||||
return graph_offset;
|
return graph_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<AnimationNode> AnimationNodeBlendTree::get_child_by_name(const StringName &p_name) {
|
Ref<AnimationNode> AnimationNodeBlendTree::get_child_by_name(const StringName &p_name) const {
|
||||||
return get_node(p_name);
|
return get_node(p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ public:
|
||||||
static Vector<String> (*get_editable_animation_list)();
|
static Vector<String> (*get_editable_animation_list)();
|
||||||
|
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
|
|
||||||
void set_animation(const StringName &p_name);
|
void set_animation(const StringName &p_name);
|
||||||
StringName get_animation() const;
|
StringName get_animation() const;
|
||||||
|
@ -150,7 +150,7 @@ public:
|
||||||
MixMode get_mix_mode() const;
|
MixMode get_mix_mode() const;
|
||||||
|
|
||||||
virtual bool has_filter() const override;
|
virtual bool has_filter() const override;
|
||||||
virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
|
|
||||||
AnimationNodeOneShot();
|
AnimationNodeOneShot();
|
||||||
};
|
};
|
||||||
|
@ -173,7 +173,7 @@ public:
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
|
|
||||||
virtual bool has_filter() const override;
|
virtual bool has_filter() const override;
|
||||||
virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
|
|
||||||
AnimationNodeAdd2();
|
AnimationNodeAdd2();
|
||||||
};
|
};
|
||||||
|
@ -193,7 +193,7 @@ public:
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
|
|
||||||
virtual bool has_filter() const override;
|
virtual bool has_filter() const override;
|
||||||
virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
|
|
||||||
AnimationNodeAdd3();
|
AnimationNodeAdd3();
|
||||||
};
|
};
|
||||||
|
@ -211,7 +211,7 @@ public:
|
||||||
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
|
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
|
||||||
|
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
|
|
||||||
virtual bool has_filter() const override;
|
virtual bool has_filter() const override;
|
||||||
AnimationNodeBlend2();
|
AnimationNodeBlend2();
|
||||||
|
@ -231,7 +231,7 @@ public:
|
||||||
|
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
|
|
||||||
double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
AnimationNodeBlend3();
|
AnimationNodeBlend3();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ public:
|
||||||
|
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
|
|
||||||
double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
|
|
||||||
AnimationNodeTimeScale();
|
AnimationNodeTimeScale();
|
||||||
};
|
};
|
||||||
|
@ -268,7 +268,7 @@ public:
|
||||||
|
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
|
|
||||||
double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
|
|
||||||
AnimationNodeTimeSeek();
|
AnimationNodeTimeSeek();
|
||||||
};
|
};
|
||||||
|
@ -332,7 +332,7 @@ public:
|
||||||
void set_allow_transition_to_self(bool p_enable);
|
void set_allow_transition_to_self(bool p_enable);
|
||||||
bool is_allow_transition_to_self() const;
|
bool is_allow_transition_to_self() const;
|
||||||
|
|
||||||
double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
|
|
||||||
AnimationNodeTransition();
|
AnimationNodeTransition();
|
||||||
};
|
};
|
||||||
|
@ -342,7 +342,7 @@ class AnimationNodeOutput : public AnimationNode {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
AnimationNodeOutput();
|
AnimationNodeOutput();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -414,14 +414,14 @@ public:
|
||||||
void get_node_connections(List<NodeConnection> *r_connections) const;
|
void get_node_connections(List<NodeConnection> *r_connections) const;
|
||||||
|
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
|
|
||||||
void get_node_list(List<StringName> *r_list);
|
void get_node_list(List<StringName> *r_list);
|
||||||
|
|
||||||
void set_graph_offset(const Vector2 &p_graph_offset);
|
void set_graph_offset(const Vector2 &p_graph_offset);
|
||||||
Vector2 get_graph_offset() const;
|
Vector2 get_graph_offset() const;
|
||||||
|
|
||||||
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) override;
|
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) const override;
|
||||||
|
|
||||||
AnimationNodeBlendTree();
|
AnimationNodeBlendTree();
|
||||||
~AnimationNodeBlendTree();
|
~AnimationNodeBlendTree();
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -100,88 +100,23 @@ public:
|
||||||
VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode)
|
VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::SwitchMode)
|
||||||
VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::AdvanceMode)
|
VARIANT_ENUM_CAST(AnimationNodeStateMachineTransition::AdvanceMode)
|
||||||
|
|
||||||
class AnimationNodeStateMachine;
|
class AnimationNodeStateMachinePlayback;
|
||||||
|
|
||||||
class AnimationNodeStateMachinePlayback : public Resource {
|
|
||||||
GDCLASS(AnimationNodeStateMachinePlayback, Resource);
|
|
||||||
|
|
||||||
friend class AnimationNodeStateMachine;
|
|
||||||
|
|
||||||
struct AStarCost {
|
|
||||||
float distance = 0.0;
|
|
||||||
StringName prev;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Transition {
|
|
||||||
StringName from;
|
|
||||||
StringName to;
|
|
||||||
StringName next;
|
|
||||||
};
|
|
||||||
|
|
||||||
double len_fade_from = 0.0;
|
|
||||||
double pos_fade_from = 0.0;
|
|
||||||
|
|
||||||
double len_current = 0.0;
|
|
||||||
double pos_current = 0.0;
|
|
||||||
bool end_loop = false;
|
|
||||||
|
|
||||||
StringName current;
|
|
||||||
Transition current_transition;
|
|
||||||
Ref<Curve> current_curve;
|
|
||||||
bool force_auto_advance = false;
|
|
||||||
|
|
||||||
StringName fading_from;
|
|
||||||
float fading_time = 0.0;
|
|
||||||
float fading_pos = 0.0;
|
|
||||||
|
|
||||||
Vector<StringName> path;
|
|
||||||
bool playing = false;
|
|
||||||
|
|
||||||
StringName start_request;
|
|
||||||
StringName travel_request;
|
|
||||||
bool reset_request = false;
|
|
||||||
bool reset_request_on_teleport = false;
|
|
||||||
bool next_request = false;
|
|
||||||
bool stop_request = false;
|
|
||||||
|
|
||||||
bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel);
|
|
||||||
void _start(const StringName &p_state);
|
|
||||||
double _process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking);
|
|
||||||
|
|
||||||
double process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking);
|
|
||||||
|
|
||||||
bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static void _bind_methods();
|
|
||||||
|
|
||||||
public:
|
|
||||||
void travel(const StringName &p_state, bool p_reset_on_teleport = true);
|
|
||||||
void start(const StringName &p_state, bool p_reset = true);
|
|
||||||
void next();
|
|
||||||
void stop();
|
|
||||||
bool is_playing() const;
|
|
||||||
StringName get_current_node() const;
|
|
||||||
StringName get_fading_from_node() const;
|
|
||||||
Vector<StringName> get_travel_path() const;
|
|
||||||
float get_current_play_pos() const;
|
|
||||||
float get_current_length() const;
|
|
||||||
|
|
||||||
float get_fade_from_play_pos() const;
|
|
||||||
float get_fade_from_length() const;
|
|
||||||
|
|
||||||
float get_fading_time() const;
|
|
||||||
float get_fading_pos() const;
|
|
||||||
|
|
||||||
AnimationNodeStateMachinePlayback();
|
|
||||||
};
|
|
||||||
|
|
||||||
class AnimationNodeStateMachine : public AnimationRootNode {
|
class AnimationNodeStateMachine : public AnimationRootNode {
|
||||||
GDCLASS(AnimationNodeStateMachine, AnimationRootNode);
|
GDCLASS(AnimationNodeStateMachine, AnimationRootNode);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum StateMachineType {
|
||||||
|
STATE_MACHINE_TYPE_ROOT,
|
||||||
|
STATE_MACHINE_TYPE_NESTED,
|
||||||
|
STATE_MACHINE_TYPE_GROUPED,
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class AnimationNodeStateMachinePlayback;
|
friend class AnimationNodeStateMachinePlayback;
|
||||||
|
|
||||||
|
StateMachineType state_machine_type = STATE_MACHINE_TYPE_ROOT;
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
Ref<AnimationRootNode> node;
|
Ref<AnimationRootNode> node;
|
||||||
Vector2 position;
|
Vector2 position;
|
||||||
|
@ -189,28 +124,24 @@ private:
|
||||||
|
|
||||||
HashMap<StringName, State> states;
|
HashMap<StringName, State> states;
|
||||||
bool allow_transition_to_self = false;
|
bool allow_transition_to_self = false;
|
||||||
|
bool reset_ends = false;
|
||||||
|
|
||||||
struct Transition {
|
struct Transition {
|
||||||
StringName from;
|
StringName from;
|
||||||
StringName to;
|
StringName to;
|
||||||
StringName local_from;
|
|
||||||
StringName local_to;
|
|
||||||
Ref<AnimationNodeStateMachineTransition> transition;
|
Ref<AnimationNodeStateMachineTransition> transition;
|
||||||
};
|
};
|
||||||
|
|
||||||
Vector<Transition> transitions;
|
Vector<Transition> transitions;
|
||||||
|
|
||||||
StringName playback = "playback";
|
StringName playback = "playback";
|
||||||
StringName state_machine_name;
|
|
||||||
AnimationNodeStateMachine *prev_state_machine = nullptr;
|
|
||||||
bool updating_transitions = false;
|
bool updating_transitions = false;
|
||||||
|
|
||||||
Vector2 graph_offset;
|
Vector2 graph_offset;
|
||||||
|
|
||||||
void _remove_transition(const Ref<AnimationNodeStateMachineTransition> p_transition);
|
void _remove_transition(const Ref<AnimationNodeStateMachineTransition> p_transition);
|
||||||
void _rename_transitions(const StringName &p_name, const StringName &p_new_name);
|
void _rename_transitions(const StringName &p_name, const StringName &p_new_name);
|
||||||
bool _can_connect(const StringName &p_name, Vector<AnimationNodeStateMachine *> p_parents = Vector<AnimationNodeStateMachine *>());
|
bool _can_connect(const StringName &p_name);
|
||||||
StringName _get_shortest_path(const StringName &p_path) const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
@ -218,6 +149,8 @@ protected:
|
||||||
bool _set(const StringName &p_name, const Variant &p_value);
|
bool _set(const StringName &p_name, const Variant &p_value);
|
||||||
bool _get(const StringName &p_name, Variant &r_ret) const;
|
bool _get(const StringName &p_name, Variant &r_ret) const;
|
||||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||||
|
void _validate_property(PropertyInfo &p_property) const;
|
||||||
|
|
||||||
bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const;
|
bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const;
|
||||||
|
|
||||||
virtual void _tree_changed() override;
|
virtual void _tree_changed() override;
|
||||||
|
@ -232,6 +165,7 @@ public:
|
||||||
|
|
||||||
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
|
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
|
||||||
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
|
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
|
||||||
|
virtual bool is_parameter_read_only(const StringName &p_parameter) const override;
|
||||||
|
|
||||||
void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2());
|
void add_node(const StringName &p_name, Ref<AnimationNode> p_node, const Vector2 &p_position = Vector2());
|
||||||
void replace_node(const StringName &p_name, Ref<AnimationNode> p_node);
|
void replace_node(const StringName &p_name, Ref<AnimationNode> p_node);
|
||||||
|
@ -248,32 +182,164 @@ public:
|
||||||
virtual void get_child_nodes(List<ChildNode> *r_child_nodes) override;
|
virtual void get_child_nodes(List<ChildNode> *r_child_nodes) override;
|
||||||
|
|
||||||
bool has_transition(const StringName &p_from, const StringName &p_to) const;
|
bool has_transition(const StringName &p_from, const StringName &p_to) const;
|
||||||
bool has_local_transition(const StringName &p_from, const StringName &p_to) const;
|
bool has_transition_from(const StringName &p_from) const;
|
||||||
|
bool has_transition_to(const StringName &p_to) const;
|
||||||
int find_transition(const StringName &p_from, const StringName &p_to) const;
|
int find_transition(const StringName &p_from, const StringName &p_to) const;
|
||||||
|
Vector<int> find_transition_from(const StringName &p_from) const;
|
||||||
|
Vector<int> find_transition_to(const StringName &p_to) const;
|
||||||
void add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition);
|
void add_transition(const StringName &p_from, const StringName &p_to, const Ref<AnimationNodeStateMachineTransition> &p_transition);
|
||||||
Ref<AnimationNodeStateMachineTransition> get_transition(int p_transition) const;
|
Ref<AnimationNodeStateMachineTransition> get_transition(int p_transition) const;
|
||||||
StringName get_transition_from(int p_transition) const;
|
StringName get_transition_from(int p_transition) const;
|
||||||
StringName get_transition_to(int p_transition) const;
|
StringName get_transition_to(int p_transition) const;
|
||||||
int get_transition_count() const;
|
int get_transition_count() const;
|
||||||
|
bool is_transition_across_group(int p_transition) const;
|
||||||
void remove_transition_by_index(const int p_transition);
|
void remove_transition_by_index(const int p_transition);
|
||||||
void remove_transition(const StringName &p_from, const StringName &p_to);
|
void remove_transition(const StringName &p_from, const StringName &p_to);
|
||||||
|
|
||||||
|
void set_state_machine_type(StateMachineType p_state_machine_type);
|
||||||
|
StateMachineType get_state_machine_type() const;
|
||||||
|
|
||||||
void set_allow_transition_to_self(bool p_enable);
|
void set_allow_transition_to_self(bool p_enable);
|
||||||
bool is_allow_transition_to_self() const;
|
bool is_allow_transition_to_self() const;
|
||||||
|
|
||||||
bool can_edit_node(const StringName &p_name) const;
|
void set_reset_ends(bool p_enable);
|
||||||
|
bool are_ends_reset() const;
|
||||||
|
|
||||||
AnimationNodeStateMachine *get_prev_state_machine() const;
|
bool can_edit_node(const StringName &p_name) const;
|
||||||
|
|
||||||
void set_graph_offset(const Vector2 &p_offset);
|
void set_graph_offset(const Vector2 &p_offset);
|
||||||
Vector2 get_graph_offset() const;
|
Vector2 get_graph_offset() const;
|
||||||
|
|
||||||
virtual double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false) override;
|
||||||
virtual String get_caption() const override;
|
virtual String get_caption() const override;
|
||||||
|
|
||||||
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) override;
|
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) const override;
|
||||||
|
|
||||||
AnimationNodeStateMachine();
|
AnimationNodeStateMachine();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
VARIANT_ENUM_CAST(AnimationNodeStateMachine::StateMachineType);
|
||||||
|
|
||||||
|
class AnimationNodeStateMachinePlayback : public Resource {
|
||||||
|
GDCLASS(AnimationNodeStateMachinePlayback, Resource);
|
||||||
|
|
||||||
|
friend class AnimationNodeStateMachine;
|
||||||
|
|
||||||
|
struct AStarCost {
|
||||||
|
float distance = 0.0;
|
||||||
|
StringName prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TransitionInfo {
|
||||||
|
StringName from;
|
||||||
|
StringName to;
|
||||||
|
StringName next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NextInfo {
|
||||||
|
StringName node;
|
||||||
|
double xfade;
|
||||||
|
Ref<Curve> curve;
|
||||||
|
AnimationNodeStateMachineTransition::SwitchMode switch_mode;
|
||||||
|
bool is_reset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChildStateMachineInfo {
|
||||||
|
Ref<AnimationNodeStateMachinePlayback> playback;
|
||||||
|
Vector<StringName> path;
|
||||||
|
bool is_reset = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
Ref<AnimationNodeStateMachineTransition> default_transition;
|
||||||
|
String base_path;
|
||||||
|
|
||||||
|
double len_fade_from = 0.0;
|
||||||
|
double pos_fade_from = 0.0;
|
||||||
|
|
||||||
|
double len_current = 0.0;
|
||||||
|
double pos_current = 0.0;
|
||||||
|
|
||||||
|
StringName current;
|
||||||
|
Ref<Curve> current_curve;
|
||||||
|
|
||||||
|
Ref<AnimationNodeStateMachineTransition> group_start_transition;
|
||||||
|
Ref<AnimationNodeStateMachineTransition> group_end_transition;
|
||||||
|
|
||||||
|
StringName fading_from;
|
||||||
|
float fading_time = 0.0;
|
||||||
|
float fading_pos = 0.0;
|
||||||
|
|
||||||
|
Vector<StringName> path;
|
||||||
|
bool playing = false;
|
||||||
|
|
||||||
|
StringName start_request;
|
||||||
|
StringName travel_request;
|
||||||
|
bool reset_request = false;
|
||||||
|
bool reset_request_on_teleport = false;
|
||||||
|
bool _reset_request_for_fading_from = false;
|
||||||
|
bool next_request = false;
|
||||||
|
bool stop_request = false;
|
||||||
|
bool teleport_request = false;
|
||||||
|
|
||||||
|
bool is_grouped = false;
|
||||||
|
|
||||||
|
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();
|
||||||
|
void _stop_main();
|
||||||
|
|
||||||
|
bool _make_travel_path(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_is_allow_transition_to_self, Vector<StringName> &r_path, bool p_test_only);
|
||||||
|
String _validate_path(AnimationNodeStateMachine *p_state_machine, const String &p_path);
|
||||||
|
bool _travel(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_is_allow_transition_to_self, bool p_test_only);
|
||||||
|
void _start(AnimationNodeStateMachine *p_state_machine);
|
||||||
|
|
||||||
|
void _clear_path_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only);
|
||||||
|
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);
|
||||||
|
void _start_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const String &p_path, bool p_test_only);
|
||||||
|
|
||||||
|
double process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only);
|
||||||
|
double _process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only);
|
||||||
|
|
||||||
|
bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const;
|
||||||
|
bool _transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only);
|
||||||
|
NextInfo _find_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine) const;
|
||||||
|
Ref<AnimationNodeStateMachineTransition> _check_group_transition(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const AnimationNodeStateMachine::Transition &p_transition, Ref<AnimationNodeStateMachine> &r_state_machine, bool &r_bypass) const;
|
||||||
|
bool _can_transition_to_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, NextInfo p_next, bool p_test_only);
|
||||||
|
|
||||||
|
void _set_current(AnimationNodeStateMachine *p_state_machine, const StringName &p_state);
|
||||||
|
void _set_grouped(bool p_is_grouped);
|
||||||
|
void _set_base_path(const String &p_base_path);
|
||||||
|
Ref<AnimationNodeStateMachinePlayback> _get_parent_playback(AnimationTree *p_tree) const;
|
||||||
|
Ref<AnimationNodeStateMachine> _get_parent_state_machine(AnimationTree *p_tree) const;
|
||||||
|
Ref<AnimationNodeStateMachineTransition> _get_group_start_transition() const;
|
||||||
|
Ref<AnimationNodeStateMachineTransition> _get_group_end_transition() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void travel(const StringName &p_state, bool p_reset_on_teleport = true);
|
||||||
|
void start(const StringName &p_state, bool p_reset = true);
|
||||||
|
void next();
|
||||||
|
void stop();
|
||||||
|
bool is_playing() const;
|
||||||
|
bool is_end() const;
|
||||||
|
StringName get_current_node() const;
|
||||||
|
StringName get_fading_from_node() const;
|
||||||
|
Vector<StringName> get_travel_path() const;
|
||||||
|
float get_current_play_pos() const;
|
||||||
|
float get_current_length() const;
|
||||||
|
|
||||||
|
float get_fade_from_play_pos() const;
|
||||||
|
float get_fade_from_length() const;
|
||||||
|
|
||||||
|
float get_fading_time() const;
|
||||||
|
float get_fading_pos() const;
|
||||||
|
|
||||||
|
void clear_path();
|
||||||
|
void push_path(const StringName &p_state);
|
||||||
|
|
||||||
|
AnimationNodeStateMachinePlayback();
|
||||||
|
};
|
||||||
|
|
||||||
#endif // ANIMATION_NODE_STATE_MACHINE_H
|
#endif // ANIMATION_NODE_STATE_MACHINE_H
|
||||||
|
|
|
@ -61,6 +61,9 @@ bool AnimationNode::is_parameter_read_only(const StringName &p_parameter) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {
|
void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {
|
||||||
|
if (is_testing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ERR_FAIL_COND(!state);
|
ERR_FAIL_COND(!state);
|
||||||
ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path));
|
ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path));
|
||||||
ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name));
|
ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name));
|
||||||
|
@ -124,13 +127,13 @@ void AnimationNode::blend_animation(const StringName &p_animation, double p_time
|
||||||
state->animation_states.push_back(anim_state);
|
state->animation_states.push_back(anim_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_is_external_seeking, const Vector<StringName> &p_connections) {
|
double AnimationNode::_pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_is_external_seeking, const Vector<StringName> &p_connections, bool p_test_only) {
|
||||||
base_path = p_base_path;
|
base_path = p_base_path;
|
||||||
parent = p_parent;
|
parent = p_parent;
|
||||||
connections = p_connections;
|
connections = p_connections;
|
||||||
state = p_state;
|
state = p_state;
|
||||||
|
|
||||||
double t = process(p_time, p_seek, p_is_external_seeking);
|
double t = process(p_time, p_seek, p_is_external_seeking, p_test_only);
|
||||||
|
|
||||||
state = nullptr;
|
state = nullptr;
|
||||||
parent = nullptr;
|
parent = nullptr;
|
||||||
|
@ -154,7 +157,7 @@ void AnimationNode::make_invalid(const String &p_reason) {
|
||||||
state->invalid_reasons += String::utf8("• ") + p_reason;
|
state->invalid_reasons += String::utf8("• ") + p_reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync) {
|
double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync, bool p_test_only) {
|
||||||
ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
|
ERR_FAIL_INDEX_V(p_input, inputs.size(), 0);
|
||||||
ERR_FAIL_COND_V(!state, 0);
|
ERR_FAIL_COND_V(!state, 0);
|
||||||
|
|
||||||
|
@ -173,7 +176,7 @@ double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool
|
||||||
|
|
||||||
//inputs.write[p_input].last_pass = state->last_pass;
|
//inputs.write[p_input].last_pass = state->last_pass;
|
||||||
real_t activity = 0.0;
|
real_t activity = 0.0;
|
||||||
double ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_is_external_seeking, p_blend, p_filter, p_sync, &activity);
|
double ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_is_external_seeking, p_blend, p_filter, p_sync, &activity, p_test_only);
|
||||||
|
|
||||||
Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path);
|
Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path);
|
||||||
|
|
||||||
|
@ -184,11 +187,11 @@ double AnimationNode::blend_input(int p_input, double p_time, bool p_seek, bool
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync) {
|
double AnimationNode::blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync, bool p_test_only) {
|
||||||
return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_is_external_seeking, p_blend, p_filter, p_sync);
|
return _blend_node(p_sub_path, Vector<StringName>(), this, p_node, p_time, p_seek, p_is_external_seeking, p_blend, p_filter, p_sync, nullptr, p_test_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync, real_t *r_max) {
|
double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync, real_t *r_max, bool p_test_only) {
|
||||||
ERR_FAIL_COND_V(!p_node.is_valid(), 0);
|
ERR_FAIL_COND_V(!p_node.is_valid(), 0);
|
||||||
ERR_FAIL_COND_V(!state, 0);
|
ERR_FAIL_COND_V(!state, 0);
|
||||||
|
|
||||||
|
@ -298,9 +301,9 @@ double AnimationNode::_blend_node(const StringName &p_subpath, const Vector<Stri
|
||||||
// This process, which depends on p_sync is needed to process sync correctly in the case of
|
// This process, which depends on p_sync is needed to process sync correctly in the case of
|
||||||
// that a synced AnimationNodeSync exists under the un-synced AnimationNodeSync.
|
// that a synced AnimationNodeSync exists under the un-synced AnimationNodeSync.
|
||||||
if (!p_seek && !p_sync && !any_valid) {
|
if (!p_seek && !p_sync && !any_valid) {
|
||||||
return p_node->_pre_process(new_path, new_parent, state, 0, p_seek, p_is_external_seeking, p_connections);
|
return p_node->_pre_process(new_path, new_parent, state, 0, p_seek, p_is_external_seeking, p_connections, p_test_only);
|
||||||
}
|
}
|
||||||
return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_is_external_seeking, p_connections);
|
return p_node->_pre_process(new_path, new_parent, state, p_time, p_seek, p_is_external_seeking, p_connections, p_test_only);
|
||||||
}
|
}
|
||||||
|
|
||||||
String AnimationNode::get_caption() const {
|
String AnimationNode::get_caption() const {
|
||||||
|
@ -354,9 +357,14 @@ int AnimationNode::find_input(const String &p_name) const {
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
double AnimationNode::process(double p_time, bool p_seek, bool p_is_external_seeking) {
|
double AnimationNode::process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
|
is_testing = p_test_only;
|
||||||
|
return _process(p_time, p_seek, p_is_external_seeking, p_test_only);
|
||||||
|
}
|
||||||
|
|
||||||
|
double AnimationNode::_process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only) {
|
||||||
double ret = 0;
|
double ret = 0;
|
||||||
GDVIRTUAL_CALL(_process, p_time, p_seek, p_is_external_seeking, ret);
|
GDVIRTUAL_CALL(_process, p_time, p_seek, p_is_external_seeking, p_test_only, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,12 +418,24 @@ void AnimationNode::_validate_property(PropertyInfo &p_property) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) {
|
Ref<AnimationNode> AnimationNode::get_child_by_name(const StringName &p_name) const {
|
||||||
Ref<AnimationNode> ret;
|
Ref<AnimationNode> ret;
|
||||||
GDVIRTUAL_CALL(_get_child_by_name, p_name, ret);
|
GDVIRTUAL_CALL(_get_child_by_name, p_name, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ref<AnimationNode> AnimationNode::find_node_by_path(const String &p_name) const {
|
||||||
|
Vector<String> split = p_name.split("/");
|
||||||
|
Ref<AnimationNode> ret = const_cast<AnimationNode *>(this);
|
||||||
|
for (int i = 0; i < split.size(); i++) {
|
||||||
|
ret = ret->get_child_by_name(split[i]);
|
||||||
|
if (!ret.is_valid()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void AnimationNode::_bind_methods() {
|
void AnimationNode::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input);
|
ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input);
|
||||||
ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input);
|
ClassDB::bind_method(D_METHOD("remove_input", "index"), &AnimationNode::remove_input);
|
||||||
|
@ -434,8 +454,8 @@ void AnimationNode::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);
|
ClassDB::bind_method(D_METHOD("_get_filters"), &AnimationNode::_get_filters);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "is_external_seeking", "blend", "looped_flag"), &AnimationNode::blend_animation, DEFVAL(Animation::LOOPED_FLAG_NONE));
|
ClassDB::bind_method(D_METHOD("blend_animation", "animation", "time", "delta", "seeked", "is_external_seeking", "blend", "looped_flag"), &AnimationNode::blend_animation, DEFVAL(Animation::LOOPED_FLAG_NONE));
|
||||||
ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "is_external_seeking", "blend", "filter", "sync"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true));
|
ClassDB::bind_method(D_METHOD("blend_node", "name", "node", "time", "seek", "is_external_seeking", "blend", "filter", "sync", "test_only"), &AnimationNode::blend_node, DEFVAL(FILTER_IGNORE), DEFVAL(true), DEFVAL(false));
|
||||||
ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "is_external_seeking", "blend", "filter", "sync"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true));
|
ClassDB::bind_method(D_METHOD("blend_input", "input_index", "time", "seek", "is_external_seeking", "blend", "filter", "sync", "test_only"), &AnimationNode::blend_input, DEFVAL(FILTER_IGNORE), DEFVAL(true), DEFVAL(false));
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("set_parameter", "name", "value"), &AnimationNode::set_parameter);
|
ClassDB::bind_method(D_METHOD("set_parameter", "name", "value"), &AnimationNode::set_parameter);
|
||||||
ClassDB::bind_method(D_METHOD("get_parameter", "name"), &AnimationNode::get_parameter);
|
ClassDB::bind_method(D_METHOD("get_parameter", "name"), &AnimationNode::get_parameter);
|
||||||
|
@ -448,7 +468,7 @@ void AnimationNode::_bind_methods() {
|
||||||
GDVIRTUAL_BIND(_get_child_by_name, "name");
|
GDVIRTUAL_BIND(_get_child_by_name, "name");
|
||||||
GDVIRTUAL_BIND(_get_parameter_default_value, "parameter");
|
GDVIRTUAL_BIND(_get_parameter_default_value, "parameter");
|
||||||
GDVIRTUAL_BIND(_is_parameter_read_only, "parameter");
|
GDVIRTUAL_BIND(_is_parameter_read_only, "parameter");
|
||||||
GDVIRTUAL_BIND(_process, "time", "seek", "is_external_seeking");
|
GDVIRTUAL_BIND(_process, "time", "seek", "is_external_seeking", "test_only");
|
||||||
GDVIRTUAL_BIND(_get_caption);
|
GDVIRTUAL_BIND(_get_caption);
|
||||||
GDVIRTUAL_BIND(_has_filter);
|
GDVIRTUAL_BIND(_has_filter);
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,8 @@
|
||||||
#include "scene/resources/animation.h"
|
#include "scene/resources/animation.h"
|
||||||
#include "scene/resources/audio_stream_polyphonic.h"
|
#include "scene/resources/audio_stream_polyphonic.h"
|
||||||
|
|
||||||
|
#define HUGE_LENGTH 31540000 // 31540000 seconds mean 1 year... is it too long? It must be longer than any Animation length and Transition xfade time to prevent time inversion.
|
||||||
|
|
||||||
class AnimationNodeBlendTree;
|
class AnimationNodeBlendTree;
|
||||||
class AnimationNodeStartState;
|
class AnimationNodeStartState;
|
||||||
class AnimationNodeEndState;
|
class AnimationNodeEndState;
|
||||||
|
@ -87,7 +89,9 @@ public:
|
||||||
Vector<real_t> blends;
|
Vector<real_t> blends;
|
||||||
State *state = nullptr;
|
State *state = nullptr;
|
||||||
|
|
||||||
double _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_is_external_seeking, const Vector<StringName> &p_connections);
|
bool is_testing = false;
|
||||||
|
|
||||||
|
double _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, double p_time, bool p_seek, bool p_is_external_seeking, const Vector<StringName> &p_connections, bool p_test_only = false);
|
||||||
|
|
||||||
//all this is temporary
|
//all this is temporary
|
||||||
StringName base_path;
|
StringName base_path;
|
||||||
|
@ -100,12 +104,15 @@ public:
|
||||||
Array _get_filters() const;
|
Array _get_filters() const;
|
||||||
void _set_filters(const Array &p_filters);
|
void _set_filters(const Array &p_filters);
|
||||||
friend class AnimationNodeBlendTree;
|
friend class AnimationNodeBlendTree;
|
||||||
double _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, real_t *r_max = nullptr);
|
double _blend_node(const StringName &p_subpath, const Vector<StringName> &p_connections, AnimationNode *p_new_parent, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, real_t *r_max = nullptr, bool p_test_only = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual double _process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false);
|
||||||
|
double process(double p_time, bool p_seek, bool p_is_external_seeking, bool p_test_only = false);
|
||||||
|
|
||||||
void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, Animation::LoopedFlag p_looped_flag = Animation::LOOPED_FLAG_NONE);
|
void blend_animation(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, Animation::LoopedFlag p_looped_flag = Animation::LOOPED_FLAG_NONE);
|
||||||
double blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true);
|
double blend_node(const StringName &p_sub_path, Ref<AnimationNode> p_node, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, bool p_test_only = false);
|
||||||
double blend_input(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true);
|
double blend_input(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, bool p_test_only = false);
|
||||||
|
|
||||||
void make_invalid(const String &p_reason);
|
void make_invalid(const String &p_reason);
|
||||||
AnimationTree *get_animation_tree() const;
|
AnimationTree *get_animation_tree() const;
|
||||||
|
@ -119,7 +126,7 @@ protected:
|
||||||
GDVIRTUAL1RC(Ref<AnimationNode>, _get_child_by_name, StringName)
|
GDVIRTUAL1RC(Ref<AnimationNode>, _get_child_by_name, StringName)
|
||||||
GDVIRTUAL1RC(Variant, _get_parameter_default_value, StringName)
|
GDVIRTUAL1RC(Variant, _get_parameter_default_value, StringName)
|
||||||
GDVIRTUAL1RC(bool, _is_parameter_read_only, StringName)
|
GDVIRTUAL1RC(bool, _is_parameter_read_only, StringName)
|
||||||
GDVIRTUAL3RC(double, _process, double, bool, bool)
|
GDVIRTUAL4RC(double, _process, double, bool, bool, bool)
|
||||||
GDVIRTUAL0RC(String, _get_caption)
|
GDVIRTUAL0RC(String, _get_caption)
|
||||||
GDVIRTUAL0RC(bool, _has_filter)
|
GDVIRTUAL0RC(bool, _has_filter)
|
||||||
|
|
||||||
|
@ -138,7 +145,6 @@ public:
|
||||||
|
|
||||||
virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
|
virtual void get_child_nodes(List<ChildNode> *r_child_nodes);
|
||||||
|
|
||||||
virtual double process(double p_time, bool p_seek, bool p_is_external_seeking);
|
|
||||||
virtual String get_caption() const;
|
virtual String get_caption() const;
|
||||||
|
|
||||||
virtual bool add_input(const String &p_name);
|
virtual bool add_input(const String &p_name);
|
||||||
|
@ -156,7 +162,8 @@ public:
|
||||||
|
|
||||||
virtual bool has_filter() const;
|
virtual bool has_filter() const;
|
||||||
|
|
||||||
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name);
|
virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) const;
|
||||||
|
Ref<AnimationNode> find_node_by_path(const String &p_name) const;
|
||||||
|
|
||||||
AnimationNode();
|
AnimationNode();
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue