mirror of https://github.com/godotengine/godot
Merge 321fca7e98 into 15ff450680
This commit is contained in:
commit
4cbef8fafe
|
|
@ -165,6 +165,9 @@
|
||||||
<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="default_transition" type="AnimationNodeStateMachineTransition" setter="set_default_transition" getter="get_default_transition">
|
||||||
|
Transition used whenever the state machine teleports.
|
||||||
|
</member>
|
||||||
<member name="reset_ends" type="bool" setter="set_reset_ends" getter="are_ends_reset" default="false">
|
<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.
|
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.
|
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.
|
||||||
|
|
|
||||||
|
|
@ -82,11 +82,26 @@
|
||||||
<method name="travel">
|
<method name="travel">
|
||||||
<return type="void" />
|
<return type="void" />
|
||||||
<param index="0" name="to_node" type="StringName" />
|
<param index="0" name="to_node" type="StringName" />
|
||||||
<param index="1" name="reset_on_teleport" type="bool" default="true" />
|
|
||||||
<description>
|
<description>
|
||||||
Transitions from the current state to another one, following the shortest path.
|
Transitions from the current state to another one, following the shortest path.
|
||||||
If the path does not connect from the current state, the animation will play after the state teleports.
|
If the path does not connect from the current state, the state machine's default transition will be used to jump directly to the destination state.
|
||||||
If [param reset_on_teleport] is [code]true[/code], the animation is played from the beginning when the travel cause a teleportation.
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="queue_travel">
|
||||||
|
<return type="void" />
|
||||||
|
<param index="0" name="to_node" type="StringName" />
|
||||||
|
<description>
|
||||||
|
Appends a series of transitions from the last state in the current travel path to another one, following the shortest path.
|
||||||
|
If the path does not connect, the state machine's default transition will be used to jump to the destination state.
|
||||||
|
</description>
|
||||||
|
</method>
|
||||||
|
<method name="queue">
|
||||||
|
<return type="void" />
|
||||||
|
<param index="0" name="to_node" type="StringName" />
|
||||||
|
<description>
|
||||||
|
Queues the requested state, using the state machine's default transition if a direct connection is not available.
|
||||||
|
|
||||||
|
You can emulate traveling with a transition by calling [code]clear_path()[/code] beforehand.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
</methods>
|
</methods>
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,27 @@ void AnimationNodeStateMachinePlayback::_set_grouped(bool p_is_grouped) {
|
||||||
void AnimationNodeStateMachinePlayback::travel(const StringName &p_state, bool p_reset_on_teleport) {
|
void AnimationNodeStateMachinePlayback::travel(const StringName &p_state, bool p_reset_on_teleport) {
|
||||||
ERR_FAIL_COND_EDMSG(is_grouped, "Grouped AnimationNodeStateMachinePlayback must be handled by parent AnimationNodeStateMachinePlayback. You need to retrieve the parent Root/Nested AnimationNodeStateMachine.");
|
ERR_FAIL_COND_EDMSG(is_grouped, "Grouped AnimationNodeStateMachinePlayback must be handled by parent AnimationNodeStateMachinePlayback. You need to retrieve the parent Root/Nested AnimationNodeStateMachine.");
|
||||||
ERR_FAIL_COND_EDMSG(String(p_state).contains("/Start") || String(p_state).contains("/End"), "Grouped AnimationNodeStateMachinePlayback doesn't allow to play Start/End directly. Instead, play the prev or next state of group in the parent AnimationNodeStateMachine.");
|
ERR_FAIL_COND_EDMSG(String(p_state).contains("/Start") || String(p_state).contains("/End"), "Grouped AnimationNodeStateMachinePlayback doesn't allow to play Start/End directly. Instead, play the prev or next state of group in the parent AnimationNodeStateMachine.");
|
||||||
_travel_main(p_state, p_reset_on_teleport);
|
|
||||||
|
reset_request_on_teleport = p_reset_on_teleport;
|
||||||
|
|
||||||
|
_travel_main(p_state, p_reset_on_teleport, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationNodeStateMachinePlayback::queue_travel(const StringName &p_state) {
|
||||||
|
ERR_FAIL_COND_EDMSG(is_grouped, "Grouped AnimationNodeStateMachinePlayback must be handled by parent AnimationNodeStateMachinePlayback. You need to retrieve the parent Root/Nested AnimationNodeStateMachine.");
|
||||||
|
ERR_FAIL_COND_EDMSG(String(p_state).contains("/Start") || String(p_state).contains("/End"), "Grouped AnimationNodeStateMachinePlayback doesn't allow to play Start/End directly. Instead, play the prev or next state of group in the parent AnimationNodeStateMachine.");
|
||||||
|
|
||||||
|
// This might be able to be a parameter on both 'travel'
|
||||||
|
// It cannot be false in 'queue_travel' otherwise the teleport would delete the queue anyway...
|
||||||
|
request_jump_instead = true;
|
||||||
|
|
||||||
|
_travel_main(p_state, false, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnimationNodeStateMachinePlayback::queue(const StringName &p_state) {
|
||||||
|
ERR_FAIL_COND_EDMSG(is_grouped, "Grouped AnimationNodeStateMachinePlayback must be handled by parent AnimationNodeStateMachinePlayback. You need to retrieve the parent Root/Nested AnimationNodeStateMachine.");
|
||||||
|
ERR_FAIL_COND_EDMSG(String(p_state).contains("/Start") || String(p_state).contains("/End"), "Grouped AnimationNodeStateMachinePlayback doesn't allow to play Start/End directly. Instead, play the prev or next state of group in the parent AnimationNodeStateMachine.");
|
||||||
|
_travel_main(p_state, false, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationNodeStateMachinePlayback::start(const StringName &p_state, bool p_reset) {
|
void AnimationNodeStateMachinePlayback::start(const StringName &p_state, bool p_reset) {
|
||||||
|
|
@ -276,10 +296,12 @@ void AnimationNodeStateMachinePlayback::stop() {
|
||||||
_stop_main();
|
_stop_main();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationNodeStateMachinePlayback::_travel_main(const StringName &p_state, bool p_reset_on_teleport) {
|
void AnimationNodeStateMachinePlayback::_travel_main(const StringName &p_state, bool p_reset_on_teleport, bool p_force_jump, bool p_retain_path) {
|
||||||
travel_request = p_state;
|
travel_request = p_state;
|
||||||
reset_request_on_teleport = p_reset_on_teleport;
|
reset_request_on_teleport = p_reset_on_teleport;
|
||||||
stop_request = false;
|
stop_request = false;
|
||||||
|
jump_request = p_force_jump;
|
||||||
|
retain_path_request = p_retain_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AnimationNodeStateMachinePlayback::_start_main(const StringName &p_state, bool p_reset) {
|
void AnimationNodeStateMachinePlayback::_start_main(const StringName &p_state, bool p_reset) {
|
||||||
|
|
@ -515,24 +537,31 @@ String AnimationNodeStateMachinePlayback::_validate_path(AnimationNodeStateMachi
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AnimationNodeStateMachinePlayback::_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) {
|
bool AnimationNodeStateMachinePlayback::_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) {
|
||||||
StringName travel = travel_request;
|
StringName travel_from;
|
||||||
|
if (retain_path_request) {
|
||||||
|
travel_from = r_path[r_path.size() - 1];
|
||||||
|
} else {
|
||||||
|
travel_from = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName travel_to = travel_request;
|
||||||
travel_request = StringName();
|
travel_request = StringName();
|
||||||
|
|
||||||
if (!playing) {
|
if (!playing) {
|
||||||
_start(p_state_machine);
|
_start(p_state_machine);
|
||||||
}
|
}
|
||||||
|
|
||||||
ERR_FAIL_COND_V(!p_state_machine->states.has(travel), false);
|
ERR_FAIL_COND_V(!p_state_machine->states.has(travel_to), false);
|
||||||
ERR_FAIL_COND_V(!p_state_machine->states.has(current), false);
|
ERR_FAIL_COND_V(!p_state_machine->states.has(travel_from), false);
|
||||||
|
|
||||||
if (current == travel) {
|
if (travel_from == travel_to) {
|
||||||
return !p_is_allow_transition_to_self;
|
return !p_is_allow_transition_to_self;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<StringName> new_path;
|
Vector<StringName> new_path;
|
||||||
|
|
||||||
Vector2 current_pos = p_state_machine->states[current].position;
|
Vector2 current_pos = p_state_machine->states[travel_from].position;
|
||||||
Vector2 target_pos = p_state_machine->states[travel].position;
|
Vector2 target_pos = p_state_machine->states[travel_to].position;
|
||||||
|
|
||||||
bool found_route = false;
|
bool found_route = false;
|
||||||
HashMap<StringName, AStarCost> cost_map;
|
HashMap<StringName, AStarCost> cost_map;
|
||||||
|
|
@ -545,16 +574,16 @@ bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (p_state_machine->transitions[i].from == current) {
|
if (p_state_machine->transitions[i].from == travel_from) {
|
||||||
open_list.push_back(i);
|
open_list.push_back(i);
|
||||||
float cost = p_state_machine->states[p_state_machine->transitions[i].to].position.distance_to(current_pos);
|
float cost = p_state_machine->states[p_state_machine->transitions[i].to].position.distance_to(current_pos);
|
||||||
cost *= p_state_machine->transitions[i].transition->get_priority();
|
cost *= p_state_machine->transitions[i].transition->get_priority();
|
||||||
AStarCost ap;
|
AStarCost ap;
|
||||||
ap.prev = current;
|
ap.prev = travel_from;
|
||||||
ap.distance = cost;
|
ap.distance = cost;
|
||||||
cost_map[p_state_machine->transitions[i].to] = ap;
|
cost_map[p_state_machine->transitions[i].to] = ap;
|
||||||
|
|
||||||
if (p_state_machine->transitions[i].to == travel) { // Prematurely found it! :D
|
if (p_state_machine->transitions[i].to == travel_to) { // Prematurely found it! :D
|
||||||
found_route = true;
|
found_route = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -567,7 +596,7 @@ bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree,
|
||||||
break; // No path found.
|
break; // No path found.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the last cost transition.
|
// Find the least cost transition.
|
||||||
List<int>::Element *least_cost_transition = nullptr;
|
List<int>::Element *least_cost_transition = nullptr;
|
||||||
float least_cost = 1e20;
|
float least_cost = 1e20;
|
||||||
|
|
||||||
|
|
@ -612,7 +641,7 @@ bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree,
|
||||||
|
|
||||||
open_list.push_back(i);
|
open_list.push_back(i);
|
||||||
|
|
||||||
if (p_state_machine->transitions[i].to == travel) {
|
if (p_state_machine->transitions[i].to == travel_to) {
|
||||||
found_route = true;
|
found_route = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -629,8 +658,8 @@ bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree,
|
||||||
// Check child grouped state machine.
|
// Check child grouped state machine.
|
||||||
if (found_route) {
|
if (found_route) {
|
||||||
// Make path.
|
// Make path.
|
||||||
StringName at = travel;
|
StringName at = travel_to;
|
||||||
while (at != current) {
|
while (at != travel_from) {
|
||||||
new_path.push_back(at);
|
new_path.push_back(at);
|
||||||
at = cost_map[at].prev;
|
at = cost_map[at].prev;
|
||||||
}
|
}
|
||||||
|
|
@ -639,7 +668,7 @@ bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree,
|
||||||
// Check internal paths of child grouped state machine.
|
// Check internal paths of child grouped state machine.
|
||||||
// For example:
|
// For example:
|
||||||
// [current - End] - [Start - End] - [Start - End] - [Start - target]
|
// [current - End] - [Start - End] - [Start - End] - [Start - target]
|
||||||
String current_path = current;
|
String current_path = travel_from;
|
||||||
int len = new_path.size() + 1;
|
int len = new_path.size() + 1;
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
Ref<AnimationNodeStateMachine> anodesm = p_state_machine->find_node_by_path(current_path);
|
Ref<AnimationNodeStateMachine> anodesm = p_state_machine->find_node_by_path(current_path);
|
||||||
|
|
@ -750,57 +779,86 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
||||||
|
|
||||||
if (travel_request != StringName()) {
|
if (travel_request != StringName()) {
|
||||||
// Fix path.
|
|
||||||
String travel_target = _validate_path(p_state_machine, travel_request);
|
String travel_target = _validate_path(p_state_machine, travel_request);
|
||||||
Vector<String> travel_path = travel_target.split("/");
|
Vector<String> travel_path = travel_target.split("/");
|
||||||
travel_request = travel_path[0];
|
travel_request = travel_path[0];
|
||||||
StringName temp_travel_request = travel_request; // For the case that can't travel.
|
StringName temp_travel_request = travel_request; // For the case that can't travel.
|
||||||
// Process children.
|
|
||||||
Vector<StringName> new_path;
|
// Do not use transitions to move to and from special states:
|
||||||
bool can_travel = _make_travel_path(tree, p_state_machine, travel_path.size() <= 1 ? p_state_machine->is_allow_transition_to_self() : false, new_path, p_test_only);
|
if (String(current).contains("/Start") || String(current).contains("/End") || String(temp_travel_request).contains("/Start") || String(temp_travel_request).contains("/End")) {
|
||||||
if (travel_path.size()) {
|
teleport_request = true;
|
||||||
if (can_travel) {
|
|
||||||
can_travel = _travel_children(tree, p_state_machine, travel_target, p_state_machine->is_allow_transition_to_self(), travel_path[0] == current, p_test_only);
|
|
||||||
} else {
|
|
||||||
_start_children(tree, p_state_machine, travel_target, p_test_only);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process to travel.
|
// If we are already not planning to use the pathfinder, we can skip the expensive A* attempt.
|
||||||
if (can_travel) {
|
if (!teleport_request && !jump_request) {
|
||||||
path = new_path;
|
// Fix path.
|
||||||
} else {
|
// Process children.
|
||||||
// Can't travel, then teleport.
|
Vector<StringName> new_path;
|
||||||
if (p_state_machine->states.has(temp_travel_request)) {
|
bool can_travel = _make_travel_path(tree, p_state_machine, travel_path.size() <= 1 ? p_state_machine->is_allow_transition_to_self() : false, new_path, p_test_only);
|
||||||
path.clear();
|
if (travel_path.size()) {
|
||||||
if (current != temp_travel_request || reset_request_on_teleport) {
|
if (can_travel) {
|
||||||
|
can_travel = _travel_children(tree, p_state_machine, travel_target, p_state_machine->is_allow_transition_to_self(), travel_path[0] == current, p_test_only);
|
||||||
|
} else {
|
||||||
|
_start_children(tree, p_state_machine, travel_target, p_test_only);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process to travel.
|
||||||
|
if (can_travel) {
|
||||||
|
if (retain_path_request) {
|
||||||
|
retain_path_request = false;
|
||||||
|
path.append_array(new_path);
|
||||||
|
} else {
|
||||||
|
path = new_path;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Can't travel via explicit transitions, then travel directly...
|
||||||
|
if (request_jump_instead) {
|
||||||
|
// using 'default_transition'.
|
||||||
|
request_jump_instead = false;
|
||||||
|
jump_request = true;
|
||||||
|
} else {
|
||||||
|
// by teleporting immediately.
|
||||||
_set_current(p_state_machine, temp_travel_request);
|
_set_current(p_state_machine, temp_travel_request);
|
||||||
reset_request = reset_request_on_teleport;
|
reset_request = reset_request_on_teleport;
|
||||||
teleport_request = true;
|
teleport_request = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jump_request) {
|
||||||
|
if (p_state_machine->states.has(temp_travel_request)) {
|
||||||
|
if (retain_path_request) {
|
||||||
|
retain_path_request = false;
|
||||||
|
} else {
|
||||||
|
path.clear();
|
||||||
|
}
|
||||||
|
if (p_state_machine->is_allow_transition_to_self() || current != temp_travel_request) {
|
||||||
|
path.push_back(temp_travel_request);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ERR_FAIL_V_MSG(AnimationNode::NodeTimeInfo(), "No such node: '" + temp_travel_request + "'");
|
ERR_FAIL_V_MSG(AnimationNode::NodeTimeInfo(), "No such node: '" + temp_travel_request + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
AnimationMixer::PlaybackInfo pi = p_playback_info;
|
if (teleport_request) {
|
||||||
|
teleport_request = false;
|
||||||
if (teleport_request) {
|
// Clear fadeing on teleport.
|
||||||
teleport_request = false;
|
fading_from = StringName();
|
||||||
// Clear fadeing on teleport.
|
fadeing_from_nti = AnimationNode::NodeTimeInfo();
|
||||||
fading_from = StringName();
|
fading_pos = 0;
|
||||||
fadeing_from_nti = AnimationNode::NodeTimeInfo();
|
// Init current length.
|
||||||
fading_pos = 0;
|
pi.time = 0;
|
||||||
// Init current length.
|
pi.seeked = true;
|
||||||
pi.time = 0;
|
pi.is_external_seeking = false;
|
||||||
pi.seeked = true;
|
pi.weight = 0;
|
||||||
pi.is_external_seeking = false;
|
current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true);
|
||||||
pi.weight = 0;
|
// Don't process first node if not necessary, instead process next node.
|
||||||
current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true);
|
_transition_to_next_recursive(tree, p_state_machine, p_delta, p_test_only);
|
||||||
// Don't process first node if not necessary, instead process next node.
|
}
|
||||||
_transition_to_next_recursive(tree, p_state_machine, p_delta, p_test_only);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check current node existence.
|
// Check current node existence.
|
||||||
|
|
@ -1058,8 +1116,24 @@ AnimationNodeStateMachinePlayback::NextInfo AnimationNodeStateMachinePlayback::_
|
||||||
next.switch_mode = ref_transition->get_switch_mode();
|
next.switch_mode = ref_transition->get_switch_mode();
|
||||||
next.is_reset = ref_transition->is_reset();
|
next.is_reset = ref_transition->is_reset();
|
||||||
next.break_loop_at_end = ref_transition->is_loop_broken_at_end();
|
next.break_loop_at_end = ref_transition->is_loop_broken_at_end();
|
||||||
|
return next; // Once we have the information we need, we can actually just return that info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// There is no transition that ends at the next state in the state machine. We can use the default transition
|
||||||
|
next.node = path[0];
|
||||||
|
if (p_state_machine->default_transition.is_null()) {
|
||||||
|
next.xfade = 0;
|
||||||
|
next.switch_mode = AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE;
|
||||||
|
next.is_reset = false;
|
||||||
|
next.break_loop_at_end = false;
|
||||||
|
} else {
|
||||||
|
next.xfade = p_state_machine->default_transition->get_xfade_time();
|
||||||
|
next.curve = p_state_machine->default_transition->get_xfade_curve();
|
||||||
|
next.switch_mode = p_state_machine->default_transition->get_switch_mode();
|
||||||
|
next.is_reset = p_state_machine->default_transition->is_reset();
|
||||||
|
next.break_loop_at_end = p_state_machine->default_transition->is_loop_broken_at_end();
|
||||||
|
}
|
||||||
|
return next; // Once we have the information we need, we can actually just return that info
|
||||||
} else {
|
} else {
|
||||||
int auto_advance_to = -1;
|
int auto_advance_to = -1;
|
||||||
float priority_best = 1e20;
|
float priority_best = 1e20;
|
||||||
|
|
@ -1198,11 +1272,6 @@ void AnimationNodeStateMachinePlayback::_bind_methods() {
|
||||||
|
|
||||||
AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() {
|
AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() {
|
||||||
set_local_to_scene(true); // Only one per instantiated scene.
|
set_local_to_scene(true); // Only one per instantiated scene.
|
||||||
default_transition.instantiate();
|
|
||||||
default_transition->set_xfade_time(0);
|
|
||||||
default_transition->set_reset(true);
|
|
||||||
default_transition->set_advance_mode(AnimationNodeStateMachineTransition::ADVANCE_MODE_AUTO);
|
|
||||||
default_transition->set_switch_mode(AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
|
|
@ -1320,6 +1389,14 @@ bool AnimationNodeStateMachine::are_ends_reset() const {
|
||||||
return reset_ends;
|
return reset_ends;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AnimationNodeStateMachine::set_default_transition(Ref<AnimationNodeStateMachineTransition> p_transition) {
|
||||||
|
default_transition = p_transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<AnimationNodeStateMachineTransition> AnimationNodeStateMachine::get_default_transition() {
|
||||||
|
return default_transition;
|
||||||
|
}
|
||||||
|
|
||||||
bool AnimationNodeStateMachine::can_edit_node(const StringName &p_name) const {
|
bool AnimationNodeStateMachine::can_edit_node(const StringName &p_name) const {
|
||||||
if (states.has(p_name)) {
|
if (states.has(p_name)) {
|
||||||
const AnimationNode *anode = states[p_name].node.ptr();
|
const AnimationNode *anode = states[p_name].node.ptr();
|
||||||
|
|
@ -1789,6 +1866,9 @@ void AnimationNodeStateMachine::get_argument_options(const StringName &p_functio
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void AnimationNodeStateMachine::_bind_methods() {
|
void AnimationNodeStateMachine::_bind_methods() {
|
||||||
|
ClassDB::bind_method(D_METHOD("set_default_transition", "transition"), &AnimationNodeStateMachine::set_default_transition);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_default_transition"), &AnimationNodeStateMachine::get_default_transition);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeStateMachine::add_node, DEFVAL(Vector2()));
|
ClassDB::bind_method(D_METHOD("add_node", "name", "node", "position"), &AnimationNodeStateMachine::add_node, DEFVAL(Vector2()));
|
||||||
ClassDB::bind_method(D_METHOD("replace_node", "name", "node"), &AnimationNodeStateMachine::replace_node);
|
ClassDB::bind_method(D_METHOD("replace_node", "name", "node"), &AnimationNodeStateMachine::replace_node);
|
||||||
ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeStateMachine::get_node);
|
ClassDB::bind_method(D_METHOD("get_node", "name"), &AnimationNodeStateMachine::get_node);
|
||||||
|
|
@ -1824,6 +1904,7 @@ void AnimationNodeStateMachine::_bind_methods() {
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "state_machine_type", PROPERTY_HINT_ENUM, "Root,Nested,Grouped"), "set_state_machine_type", "get_state_machine_type");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "state_machine_type", PROPERTY_HINT_ENUM, "Root,Nested,Grouped"), "set_state_machine_type", "get_state_machine_type");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_transition_to_self"), "set_allow_transition_to_self", "is_allow_transition_to_self");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_transition_to_self"), "set_allow_transition_to_self", "is_allow_transition_to_self");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset_ends"), "set_reset_ends", "are_ends_reset");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset_ends"), "set_reset_ends", "are_ends_reset");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "default_transition", PROPERTY_HINT_RESOURCE_TYPE, "AnimationNodeStateMachineTransition"), "set_default_transition", "get_default_transition");
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(STATE_MACHINE_TYPE_ROOT);
|
BIND_ENUM_CONSTANT(STATE_MACHINE_TYPE_ROOT);
|
||||||
BIND_ENUM_CONSTANT(STATE_MACHINE_TYPE_NESTED);
|
BIND_ENUM_CONSTANT(STATE_MACHINE_TYPE_NESTED);
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,7 @@ private:
|
||||||
Ref<AnimationNodeStateMachineTransition> transition;
|
Ref<AnimationNodeStateMachineTransition> transition;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Ref<AnimationNodeStateMachineTransition> default_transition;
|
||||||
Vector<Transition> transitions;
|
Vector<Transition> transitions;
|
||||||
|
|
||||||
StringName playback = "playback";
|
StringName playback = "playback";
|
||||||
|
|
@ -206,6 +207,9 @@ public:
|
||||||
void set_reset_ends(bool p_enable);
|
void set_reset_ends(bool p_enable);
|
||||||
bool are_ends_reset() const;
|
bool are_ends_reset() const;
|
||||||
|
|
||||||
|
void set_default_transition(Ref<AnimationNodeStateMachineTransition> p_transition);
|
||||||
|
Ref<AnimationNodeStateMachineTransition> get_default_transition();
|
||||||
|
|
||||||
bool can_edit_node(const StringName &p_name) 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);
|
||||||
|
|
@ -259,7 +263,6 @@ class AnimationNodeStateMachinePlayback : public Resource {
|
||||||
bool is_reset = false;
|
bool is_reset = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Ref<AnimationNodeStateMachineTransition> default_transition;
|
|
||||||
String base_path;
|
String base_path;
|
||||||
|
|
||||||
AnimationNode::NodeTimeInfo current_nti;
|
AnimationNode::NodeTimeInfo current_nti;
|
||||||
|
|
@ -284,11 +287,14 @@ class AnimationNodeStateMachinePlayback : public Resource {
|
||||||
bool _reset_request_for_fading_from = false;
|
bool _reset_request_for_fading_from = false;
|
||||||
bool next_request = false;
|
bool next_request = false;
|
||||||
bool stop_request = false;
|
bool stop_request = false;
|
||||||
|
bool request_jump_instead = false;
|
||||||
bool teleport_request = false;
|
bool teleport_request = false;
|
||||||
|
bool jump_request = false;
|
||||||
|
bool retain_path_request = false;
|
||||||
|
|
||||||
bool is_grouped = false;
|
bool is_grouped = false;
|
||||||
|
|
||||||
void _travel_main(const StringName &p_state, bool p_reset_on_teleport = true);
|
void _travel_main(const StringName &p_state, bool p_reset_on_teleport = true, bool p_force_jump = false, bool p_retain_path = false);
|
||||||
void _start_main(const StringName &p_state, bool p_reset = true);
|
void _start_main(const StringName &p_state, bool p_reset = true);
|
||||||
void _next_main();
|
void _next_main();
|
||||||
void _stop_main();
|
void _stop_main();
|
||||||
|
|
@ -326,6 +332,8 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void travel(const StringName &p_state, bool p_reset_on_teleport = true);
|
void travel(const StringName &p_state, bool p_reset_on_teleport = true);
|
||||||
|
void queue_travel(const StringName &p_state);
|
||||||
|
void queue(const StringName &p_state);
|
||||||
void start(const StringName &p_state, bool p_reset = true);
|
void start(const StringName &p_state, bool p_reset = true);
|
||||||
void next();
|
void next();
|
||||||
void stop();
|
void stop();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue