|
@@ -107,6 +107,15 @@ Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const {
|
|
|
return xfade_curve;
|
|
|
}
|
|
|
|
|
|
+void AnimationNodeStateMachineTransition::set_reset(bool p_reset) {
|
|
|
+ reset = p_reset;
|
|
|
+ emit_changed();
|
|
|
+}
|
|
|
+
|
|
|
+bool AnimationNodeStateMachineTransition::is_reset() const {
|
|
|
+ return reset;
|
|
|
+}
|
|
|
+
|
|
|
void AnimationNodeStateMachineTransition::set_priority(int p_priority) {
|
|
|
priority = p_priority;
|
|
|
emit_changed();
|
|
@@ -132,6 +141,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeStateMachineTransition::set_xfade_curve);
|
|
|
ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeStateMachineTransition::get_xfade_curve);
|
|
|
|
|
|
+ ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeStateMachineTransition::set_reset);
|
|
|
+ ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeStateMachineTransition::is_reset);
|
|
|
+
|
|
|
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &AnimationNodeStateMachineTransition::set_priority);
|
|
|
ClassDB::bind_method(D_METHOD("get_priority"), &AnimationNodeStateMachineTransition::get_priority);
|
|
|
|
|
@@ -140,6 +152,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
|
|
|
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
|
|
|
+
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset"), "set_reset", "is_reset");
|
|
|
+
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority");
|
|
|
ADD_GROUP("Switch", "");
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,At End"), "set_switch_mode", "get_switch_mode");
|
|
@@ -164,18 +179,27 @@ AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() {
|
|
|
|
|
|
////////////////////////////////////////////////////////
|
|
|
|
|
|
-void AnimationNodeStateMachinePlayback::travel(const StringName &p_state) {
|
|
|
- start_request_travel = true;
|
|
|
- start_request = p_state;
|
|
|
+void AnimationNodeStateMachinePlayback::travel(const StringName &p_state, bool p_reset_on_teleport) {
|
|
|
+ travel_request = p_state;
|
|
|
+ reset_request_on_teleport = p_reset_on_teleport;
|
|
|
stop_request = false;
|
|
|
}
|
|
|
|
|
|
-void AnimationNodeStateMachinePlayback::start(const StringName &p_state) {
|
|
|
- start_request_travel = false;
|
|
|
+void AnimationNodeStateMachinePlayback::start(const StringName &p_state, bool p_reset) {
|
|
|
+ travel_request = StringName();
|
|
|
+ reset_request = p_reset;
|
|
|
+ _start(p_state);
|
|
|
+}
|
|
|
+
|
|
|
+void AnimationNodeStateMachinePlayback::_start(const StringName &p_state) {
|
|
|
start_request = p_state;
|
|
|
stop_request = false;
|
|
|
}
|
|
|
|
|
|
+void AnimationNodeStateMachinePlayback::next() {
|
|
|
+ next_request = true;
|
|
|
+}
|
|
|
+
|
|
|
void AnimationNodeStateMachinePlayback::stop() {
|
|
|
stop_request = true;
|
|
|
}
|
|
@@ -323,6 +347,15 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
|
|
|
}
|
|
|
|
|
|
double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking) {
|
|
|
+ double rem = _process(p_state_machine, p_time, p_seek, p_is_external_seeking);
|
|
|
+ start_request = StringName();
|
|
|
+ next_request = false;
|
|
|
+ stop_request = false;
|
|
|
+ reset_request_on_teleport = false;
|
|
|
+ return rem;
|
|
|
+}
|
|
|
+
|
|
|
+double AnimationNodeStateMachinePlayback::_process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking) {
|
|
|
if (p_time == -1) {
|
|
|
Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node;
|
|
|
if (anodesm.is_valid()) {
|
|
@@ -335,14 +368,13 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
|
|
|
//if not playing and it can restart, then restart
|
|
|
if (!playing && start_request == StringName()) {
|
|
|
if (!stop_request && p_state_machine->start_node) {
|
|
|
- start(p_state_machine->start_node);
|
|
|
+ _start(p_state_machine->start_node);
|
|
|
} else {
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (playing && stop_request) {
|
|
|
- stop_request = false;
|
|
|
playing = false;
|
|
|
return 0;
|
|
|
}
|
|
@@ -350,42 +382,45 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
|
|
|
bool play_start = false;
|
|
|
|
|
|
if (start_request != StringName()) {
|
|
|
- if (start_request_travel) {
|
|
|
- if (!playing) {
|
|
|
- if (!stop_request && p_state_machine->start_node) {
|
|
|
- // can restart, just postpone traveling
|
|
|
- path.clear();
|
|
|
- current = p_state_machine->start_node;
|
|
|
- playing = true;
|
|
|
- play_start = true;
|
|
|
- } else {
|
|
|
- // stopped, invalid state
|
|
|
- String node_name = start_request;
|
|
|
- start_request = StringName(); //clear start request
|
|
|
- ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing. Maybe you need to enable Autoplay on Load for one of the nodes in your state machine or call .start() first?");
|
|
|
- }
|
|
|
- } else {
|
|
|
- if (!_travel(p_state_machine, start_request)) {
|
|
|
- // can't travel, then teleport
|
|
|
- path.clear();
|
|
|
- current = start_request;
|
|
|
- play_start = true;
|
|
|
- }
|
|
|
- start_request = StringName(); //clear start request
|
|
|
- }
|
|
|
+ // teleport to start
|
|
|
+ if (p_state_machine->states.has(start_request)) {
|
|
|
+ path.clear();
|
|
|
+ current = start_request;
|
|
|
+ playing = true;
|
|
|
+ play_start = true;
|
|
|
} else {
|
|
|
- // teleport to start
|
|
|
- if (p_state_machine->states.has(start_request)) {
|
|
|
+ StringName node = start_request;
|
|
|
+ ERR_FAIL_V_MSG(0, "No such node: '" + node + "'");
|
|
|
+ }
|
|
|
+ } else if (travel_request != StringName()) {
|
|
|
+ if (!playing) {
|
|
|
+ if (!stop_request && p_state_machine->start_node) {
|
|
|
+ // can restart, just postpone traveling
|
|
|
path.clear();
|
|
|
- current = start_request;
|
|
|
+ current = p_state_machine->start_node;
|
|
|
playing = true;
|
|
|
play_start = true;
|
|
|
- start_request = StringName(); //clear start request
|
|
|
} else {
|
|
|
- StringName node = start_request;
|
|
|
- start_request = StringName(); //clear start request
|
|
|
- ERR_FAIL_V_MSG(0, "No such node: '" + node + "'");
|
|
|
+ // stopped, invalid state
|
|
|
+ String node_name = travel_request;
|
|
|
+ travel_request = StringName();
|
|
|
+ ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing. Maybe you need to enable Autoplay on Load for one of the nodes in your state machine or call .start() first?");
|
|
|
}
|
|
|
+ } else {
|
|
|
+ if (!_travel(p_state_machine, travel_request)) {
|
|
|
+ // can't travel, then teleport
|
|
|
+ if (p_state_machine->states.has(travel_request)) {
|
|
|
+ path.clear();
|
|
|
+ current = travel_request;
|
|
|
+ play_start = true;
|
|
|
+ reset_request = reset_request_on_teleport;
|
|
|
+ } else {
|
|
|
+ StringName node = travel_request;
|
|
|
+ travel_request = StringName();
|
|
|
+ ERR_FAIL_V_MSG(0, "No such node: '" + node + "'");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ travel_request = StringName();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -396,8 +431,11 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
|
|
|
current = p_state_machine->start_node;
|
|
|
}
|
|
|
|
|
|
- len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 1.0, AnimationNode::FILTER_IGNORE, true);
|
|
|
- pos_current = 0;
|
|
|
+ if (reset_request) {
|
|
|
+ len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 1.0, AnimationNode::FILTER_IGNORE, true);
|
|
|
+ pos_current = 0;
|
|
|
+ reset_request = false;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (!p_state_machine->states.has(current)) {
|
|
@@ -421,7 +459,8 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
|
|
|
if (current_curve.is_valid()) {
|
|
|
fade_blend = current_curve->sample(fade_blend);
|
|
|
}
|
|
|
- double rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
|
|
+
|
|
|
+ double rem = do_start ? len_current : p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
|
|
|
|
|
|
if (fading_from != StringName()) {
|
|
|
double fade_blend_inv = 1.0 - fade_blend;
|
|
@@ -457,6 +496,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
|
|
|
next_xfade = p_state_machine->transitions[i].transition->get_xfade_time();
|
|
|
current_curve = p_state_machine->transitions[i].transition->get_xfade_curve();
|
|
|
switch_mode = p_state_machine->transitions[i].transition->get_switch_mode();
|
|
|
+ reset_request = p_state_machine->transitions[i].transition->is_reset();
|
|
|
next = path[0];
|
|
|
}
|
|
|
}
|
|
@@ -513,6 +553,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
|
|
|
current_curve = p_state_machine->transitions[auto_advance_to].transition->get_xfade_curve();
|
|
|
next_xfade = p_state_machine->transitions[auto_advance_to].transition->get_xfade_time();
|
|
|
switch_mode = p_state_machine->transitions[auto_advance_to].transition->get_switch_mode();
|
|
|
+ reset_request = p_state_machine->transitions[auto_advance_to].transition->is_reset();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -567,7 +608,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
|
|
|
goto_next = fading_from == StringName();
|
|
|
}
|
|
|
|
|
|
- if (goto_next) { //end_loop should be used because fade time may be too small or zero and animation may have looped
|
|
|
+ if (next_request || goto_next) { //end_loop should be used because fade time may be too small or zero and animation may have looped
|
|
|
if (next_xfade) {
|
|
|
//time to fade, baby
|
|
|
fading_from = current;
|
|
@@ -591,7 +632,9 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
|
|
|
|
|
|
current = next;
|
|
|
|
|
|
- len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, CMP_EPSILON, AnimationNode::FILTER_IGNORE, true); // Process next node's first key in here.
|
|
|
+ if (reset_request) {
|
|
|
+ len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, CMP_EPSILON, AnimationNode::FILTER_IGNORE, true); // Process next node's first key in here.
|
|
|
+ }
|
|
|
if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
|
|
|
pos_current = MIN(pos_current, len_current);
|
|
|
p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true);
|
|
@@ -652,8 +695,9 @@ bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<Anima
|
|
|
}
|
|
|
|
|
|
void AnimationNodeStateMachinePlayback::_bind_methods() {
|
|
|
- ClassDB::bind_method(D_METHOD("travel", "to_node"), &AnimationNodeStateMachinePlayback::travel);
|
|
|
- ClassDB::bind_method(D_METHOD("start", "node"), &AnimationNodeStateMachinePlayback::start);
|
|
|
+ ClassDB::bind_method(D_METHOD("travel", "to_node", "reset_on_teleport"), &AnimationNodeStateMachinePlayback::travel, DEFVAL(true));
|
|
|
+ ClassDB::bind_method(D_METHOD("start", "node", "reset"), &AnimationNodeStateMachinePlayback::start, DEFVAL(true));
|
|
|
+ ClassDB::bind_method(D_METHOD("next"), &AnimationNodeStateMachinePlayback::next);
|
|
|
ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeStateMachinePlayback::stop);
|
|
|
ClassDB::bind_method(D_METHOD("is_playing"), &AnimationNodeStateMachinePlayback::is_playing);
|
|
|
ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachinePlayback::get_current_node);
|