diff options
Diffstat (limited to 'scene/animation/animation_node_state_machine.cpp')
-rw-r--r-- | scene/animation/animation_node_state_machine.cpp | 138 |
1 files changed, 65 insertions, 73 deletions
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index ec44641484..0484694555 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -101,12 +101,22 @@ float AnimationNodeStateMachineTransition::get_xfade_time() const { void AnimationNodeStateMachineTransition::set_xfade_curve(const Ref<Curve> &p_curve) { xfade_curve = p_curve; + emit_changed(); } Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const { return xfade_curve; } +void AnimationNodeStateMachineTransition::set_break_loop_at_end(bool p_enable) { + break_loop_at_end = p_enable; + emit_changed(); +} + +bool AnimationNodeStateMachineTransition::is_loop_broken_at_end() const { + return break_loop_at_end; +} + void AnimationNodeStateMachineTransition::set_reset(bool p_reset) { reset = p_reset; emit_changed(); @@ -141,6 +151,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_break_loop_at_end", "enable"), &AnimationNodeStateMachineTransition::set_break_loop_at_end); + ClassDB::bind_method(D_METHOD("is_loop_broken_at_end"), &AnimationNodeStateMachineTransition::is_loop_broken_at_end); + ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeStateMachineTransition::set_reset); ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeStateMachineTransition::is_reset); @@ -153,6 +166,7 @@ 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, "break_loop_at_end"), "set_break_loop_at_end", "is_loop_broken_at_end"); 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"); @@ -310,19 +324,19 @@ TypedArray<StringName> AnimationNodeStateMachinePlayback::_get_travel_path() con } float AnimationNodeStateMachinePlayback::get_current_play_pos() const { - return pos_current; + return current_nti.position; } float AnimationNodeStateMachinePlayback::get_current_length() const { - return len_current; + return current_nti.length; } float AnimationNodeStateMachinePlayback::get_fade_from_play_pos() const { - return pos_fade_from; + return fadeing_from_nti.position; } float AnimationNodeStateMachinePlayback::get_fade_from_length() const { - return len_fade_from; + return fadeing_from_nti.length; } float AnimationNodeStateMachinePlayback::get_fading_time() const { @@ -665,21 +679,22 @@ bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree, } } -double AnimationNodeStateMachinePlayback::process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { - double rem = _process(p_base_path, p_state_machine, p_playback_info, p_test_only); +AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { + AnimationNode::NodeTimeInfo nti = _process(p_base_path, p_state_machine, p_playback_info, p_test_only); start_request = StringName(); next_request = false; stop_request = false; reset_request_on_teleport = false; - return rem; + return nti; } -double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { _set_base_path(p_base_path); AnimationTree *tree = p_state_machine->process_state->tree; double p_time = p_playback_info.time; + double p_delta = p_playback_info.delta; bool p_seek = p_playback_info.seeked; bool p_is_external_seeking = p_playback_info.is_external_seeking; @@ -690,8 +705,8 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An if (p_state_machine->get_state_machine_type() != AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) { path.clear(); _clear_path_children(tree, p_state_machine, p_test_only); - _start(p_state_machine); } + _start(p_state_machine); reset_request = true; } else { // Reset current state. @@ -705,11 +720,11 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An travel_request = StringName(); path.clear(); playing = false; - return 0; + return AnimationNode::NodeTimeInfo(); } if (!playing && start_request != StringName() && travel_request != StringName()) { - return 0; + return AnimationNode::NodeTimeInfo(); } // Process start/travel request. @@ -732,7 +747,7 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An _start(p_state_machine); } else { StringName node = start_request; - ERR_FAIL_V_MSG(0, "No such node: '" + node + "'"); + ERR_FAIL_V_MSG(AnimationNode::NodeTimeInfo(), "No such node: '" + node + "'"); } } @@ -766,7 +781,7 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An teleport_request = true; } } else { - ERR_FAIL_V_MSG(0, "No such node: '" + temp_travel_request + "'"); + ERR_FAIL_V_MSG(AnimationNode::NodeTimeInfo(), "No such node: '" + temp_travel_request + "'"); } } } @@ -777,16 +792,14 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An teleport_request = false; // Clear fadeing on teleport. fading_from = StringName(); + fadeing_from_nti = AnimationNode::NodeTimeInfo(); fading_pos = 0; // Init current length. - pos_current = 0; // Overwritten suddenly in main process. - pi.time = 0; pi.seeked = true; pi.is_external_seeking = false; pi.weight = 0; - - len_current = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); + current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); // Don't process first node if not necessary, insteads process next node. _transition_to_next_recursive(tree, p_state_machine, p_test_only); } @@ -795,7 +808,7 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An if (!p_state_machine->states.has(current)) { playing = false; // Current does not exist. _set_current(p_state_machine, StringName()); - return 0; + return AnimationNode::NodeTimeInfo(); } // Special case for grouped state machine Start/End to make priority with parent blend (means don't treat Start and End states as RESET animations). @@ -813,7 +826,7 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An fading_from = StringName(); } else { if (!p_seek) { - fading_pos += p_time; + fading_pos += Math::abs(p_delta); } fade_blend = MIN(1.0, fading_pos / fading_time); } @@ -829,18 +842,14 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An } // Main process. - double rem = 0.0; pi = p_playback_info; pi.weight = fade_blend; if (reset_request) { reset_request = false; pi.time = 0; pi.seeked = true; - len_current = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); - rem = len_current; - } else { - rem = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. } + current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. // Cross-fade process. if (fading_from != StringName()) { @@ -852,7 +861,6 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An fade_blend_inv = 1.0; } - float fading_from_rem = 0.0; pi = p_playback_info; pi.weight = fade_blend_inv; if (_reset_request_for_fading_from) { @@ -860,57 +868,41 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An pi.time = 0; pi.seeked = true; } - fading_from_rem = p_state_machine->blend_node(p_state_machine->states[fading_from].node, fading_from, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. - - // Guess playback position. - if (fading_from_rem > len_fade_from) { /// Weird but ok. - len_fade_from = fading_from_rem; - } - pos_fade_from = len_fade_from - fading_from_rem; + fadeing_from_nti = p_state_machine->blend_node(p_state_machine->states[fading_from].node, fading_from, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. if (fading_pos >= fading_time) { - fading_from = StringName(); // Finish fading. + // Finish fading. + fading_from = StringName(); + fadeing_from_nti = AnimationNode::NodeTimeInfo(); } } - // Guess playback position. - if (rem > len_current) { // Weird but ok. - len_current = rem; - } - pos_current = len_current - rem; - // Find next and see when to transition. _transition_to_next_recursive(tree, p_state_machine, p_test_only); // Predict remaining time. - double remain = rem; // If we can't predict the end of state machine, the time remaining must be INFINITY. - if (p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) { // There is no next transition. if (!p_state_machine->has_transition_from(current)) { if (fading_from != StringName()) { - remain = MAX(rem, fading_time - fading_pos); - } else { - remain = rem; + return current_nti.get_remain() > fadeing_from_nti.get_remain() ? current_nti : fadeing_from_nti; } - return remain; + return current_nti; } } if (current == p_state_machine->end_node) { - if (fading_from != StringName()) { - remain = MAX(0, fading_time - fading_pos); - } else { - remain = 0; + if (fading_from != StringName() && fadeing_from_nti.get_remain() > 0) { + return fadeing_from_nti; } - return remain; + return AnimationNode::NodeTimeInfo(); } if (!is_end()) { - return HUGE_LENGTH; + current_nti.is_infinity = true; } - return remain; + return current_nti; } bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only) { @@ -952,6 +944,7 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); } fading_from = StringName(); + fadeing_from_nti = AnimationNode::NodeTimeInfo(); fading_time = 0; fading_pos = 0; } @@ -968,11 +961,10 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT _reset_request_for_fading_from = reset_request; // To avoid processing doubly, it must be reset in the fading process within _process(). reset_request = next.is_reset; - pos_fade_from = pos_current; - len_fade_from = len_current; + fadeing_from_nti = current_nti; if (next.switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) { - pi.time = MIN(pos_current, len_current); + pi.time = current_nti.position; pi.seeked = true; pi.is_external_seeking = false; pi.weight = 0; @@ -980,24 +972,11 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT } // Just get length to find next recursive. - double rem = 0.0; pi.time = 0; pi.is_external_seeking = false; pi.weight = 0; - if (next.is_reset) { - pi.seeked = true; - len_current = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); // Just retrieve remain length, don't process. - rem = len_current; - } else { - pi.seeked = false; - rem = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); // Just retrieve remain length, don't process. - } - - // Guess playback position. - if (rem > len_current) { // Weird but ok. - len_current = rem; - } - pos_current = len_current - rem; + pi.seeked = next.is_reset; + current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); // Just retrieve remain length, don't process. // Fading must be processed. if (fading_time) { @@ -1028,6 +1007,7 @@ bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p playback->_next_main(); // Then, fadeing should be end. fading_from = StringName(); + fadeing_from_nti = AnimationNode::NodeTimeInfo(); fading_pos = 0; } else { return true; @@ -1039,7 +1019,7 @@ bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p } if (current != p_state_machine->start_node && p_next.switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_AT_END) { - return pos_current >= len_current - p_next.xfade; + return current_nti.get_remain(p_next.break_loop_at_end) <= p_next.xfade; } return true; } @@ -1084,6 +1064,7 @@ AnimationNodeStateMachinePlayback::NextInfo AnimationNodeStateMachinePlayback::_ next.curve = ref_transition->get_xfade_curve(); next.switch_mode = ref_transition->get_switch_mode(); next.is_reset = ref_transition->is_reset(); + next.break_loop_at_end = ref_transition->is_loop_broken_at_end(); } } } else { @@ -1113,6 +1094,7 @@ AnimationNodeStateMachinePlayback::NextInfo AnimationNodeStateMachinePlayback::_ next.curve = ref_transition->get_xfade_curve(); next.switch_mode = ref_transition->get_switch_mode(); next.is_reset = ref_transition->is_reset(); + next.break_loop_at_end = ref_transition->is_loop_broken_at_end(); } } @@ -1233,6 +1215,7 @@ AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() { /////////////////////////////////////////////////////// void AnimationNodeStateMachine::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::OBJECT, playback, PROPERTY_HINT_RESOURCE_TYPE, "AnimationNodeStateMachinePlayback", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ALWAYS_DUPLICATE)); // Don't store this object in .tres, it always needs to be made as unique object. List<StringName> advance_conditions; for (int i = 0; i < transitions.size(); i++) { @@ -1249,6 +1232,11 @@ void AnimationNodeStateMachine::get_parameter_list(List<PropertyInfo> *r_list) c } Variant AnimationNodeStateMachine::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + if (p_parameter == playback) { Ref<AnimationNodeStateMachinePlayback> p; p.instantiate(); @@ -1259,6 +1247,10 @@ Variant AnimationNodeStateMachine::get_parameter_default_value(const StringName } bool AnimationNodeStateMachine::is_parameter_read_only(const StringName &p_parameter) const { + if (AnimationNode::is_parameter_read_only(p_parameter)) { + return true; + } + if (p_parameter == playback) { return true; } @@ -1622,9 +1614,9 @@ Vector2 AnimationNodeStateMachine::get_graph_offset() const { return graph_offset; } -double AnimationNodeStateMachine::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeStateMachine::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { Ref<AnimationNodeStateMachinePlayback> playback_new = get_parameter(playback); - ERR_FAIL_COND_V(playback_new.is_null(), 0.0); + ERR_FAIL_COND_V(playback_new.is_null(), AnimationNode::NodeTimeInfo()); playback_new->_set_grouped(state_machine_type == STATE_MACHINE_TYPE_GROUPED); if (p_test_only) { playback_new = playback_new->duplicate(); // Don't process original when testing. |