diff options
-rw-r--r-- | editor/plugins/animation_player_editor_plugin.cpp | 10 | ||||
-rw-r--r-- | editor/plugins/animation_state_machine_editor.cpp | 12 | ||||
-rw-r--r-- | scene/animation/animation_node_state_machine.cpp | 73 | ||||
-rw-r--r-- | scene/animation/animation_node_state_machine.h | 6 | ||||
-rw-r--r-- | scene/animation/animation_player.cpp | 27 | ||||
-rw-r--r-- | scene/animation/animation_player.h | 4 |
6 files changed, 69 insertions, 63 deletions
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 5d60de973a..f64c4532a1 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -248,7 +248,7 @@ void AnimationPlayerEditor::_play_from_pressed() { player->clear_caches(); //so it won't blend with itself } ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing."); - player->seek(time, true, true); + player->seek_internal(time, true, true, true); player->play(current); } @@ -286,7 +286,7 @@ void AnimationPlayerEditor::_play_bw_from_pressed() { player->clear_caches(); //so it won't blend with itself } ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing."); - player->seek(time, true, true); + player->seek_internal(time, true, true, true); player->play_backwards(current); } @@ -1296,7 +1296,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_timeline_o pos = CLAMP(pos, 0, (double)anim->get_length() - CMP_EPSILON2); // Hack: Avoid fposmod with LOOP_LINEAR. if (!p_timeline_only && anim.is_valid()) { - player->seek(pos, true, true); + player->seek_internal(pos, true, true, false); } track_editor->set_anim_pos(pos); @@ -1707,7 +1707,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2_step_prepare(int p_step_offs bool valid = anim->get_loop_mode() != Animation::LOOP_NONE || (pos >= 0 && pos <= anim->get_length()); onion.captures_valid[p_capture_idx] = valid; if (valid) { - player->seek(pos, true, true); + player->seek_internal(pos, true, true, false); OS::get_singleton()->get_main_loop()->process(0); // This is the key: process the frame and let all callbacks/updates/notifications happen // so everything (transforms, skeletons, etc.) is up-to-date visually. @@ -1764,7 +1764,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2_epilog() { // backed by a proper reset animation will work correctly with onion // skinning and the possibility to restore the values mentioned in the // first point above is gone. Still good enough. - player->seek(onion.temp.anim_player_position, true, true); + player->seek_internal(onion.temp.anim_player_position, true, true, false); player->restore(onion.temp.anim_values_backup); // Restore state of main editors. diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 7d81ae695a..e9dd54f73b 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -618,7 +618,7 @@ bool AnimationNodeStateMachineEditor::_create_submenu(PopupMenu *p_menu, Ref<Ani if (ansm == state_machine) { end_menu->add_item(E, nodes_to_connect.size()); - nodes_to_connect.push_back(state_machine->end_node); + nodes_to_connect.push_back(AnimationNodeStateMachine::END_NODE); continue; } @@ -1111,10 +1111,10 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { Ref<StyleBox> node_frame_style = is_selected ? theme_cache.node_frame_selected : theme_cache.node_frame; state_machine_draw->draw_style_box(node_frame_style, nr.node); - if (!is_selected && state_machine->start_node == name) { + if (!is_selected && AnimationNodeStateMachine::START_NODE == name) { state_machine_draw->draw_style_box(theme_cache.node_frame_start, nr.node); } - if (!is_selected && state_machine->end_node == name) { + if (!is_selected && AnimationNodeStateMachine::END_NODE == name) { state_machine_draw->draw_style_box(theme_cache.node_frame_end, nr.node); } if (playing && (blend_from == name || current == name || travel_path.has(name))) { @@ -1188,7 +1188,7 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(const S return; } - if (p_name == state_machine->start_node || p_name == state_machine->end_node || p_name.is_empty()) { + if (p_name == AnimationNodeStateMachine::START_NODE || p_name == AnimationNodeStateMachine::END_NODE || p_name.is_empty()) { return; } @@ -1523,7 +1523,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action undo_redo->create_action(TTR("Node Removed")); for (int i = 0; i < node_rects.size(); i++) { - if (node_rects[i].node_name == state_machine->start_node || node_rects[i].node_name == state_machine->end_node) { + if (node_rects[i].node_name == AnimationNodeStateMachine::START_NODE || node_rects[i].node_name == AnimationNodeStateMachine::END_NODE) { continue; } @@ -1583,7 +1583,7 @@ void AnimationNodeStateMachineEditor::_update_mode() { if (tool_select->is_pressed()) { selection_tools_hb->show(); 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() == AnimationNodeStateMachine::START_NODE || *selected_nodes.begin() == AnimationNodeStateMachine::END_NODE); tool_erase->set_disabled(nothing_selected || start_end_selected || read_only); } else { selection_tools_hb->hide(); diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 87574a66ed..8b497abd8c 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -31,6 +31,9 @@ #include "animation_node_state_machine.h" #include "scene/main/window.h" +StringName AnimationNodeStateMachine::START_NODE; +StringName AnimationNodeStateMachine::END_NODE; + ///////////////////////////////////////////////// void AnimationNodeStateMachineTransition::set_switch_mode(SwitchMode p_mode) { @@ -226,9 +229,9 @@ void AnimationNodeStateMachinePlayback::_set_current(AnimationNodeStateMachine * // Validation. if (anodesm->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) { - indices = anodesm->find_transition_from(anodesm->start_node); + indices = anodesm->find_transition_from(AnimationNodeStateMachine::START_NODE); int anodesm_start_size = indices.size(); - indices = anodesm->find_transition_to(anodesm->end_node); + indices = anodesm->find_transition_to(AnimationNodeStateMachine::END_NODE); int anodesm_end_size = indices.size(); if (group_start_size > 1) { WARN_PRINT_ED("There are two or more transitions to the Grouped AnimationNodeStateMachine in AnimationNodeStateMachine: " + base_path + ", which may result in unintended transitions."); @@ -304,7 +307,7 @@ bool AnimationNodeStateMachinePlayback::is_playing() const { } bool AnimationNodeStateMachinePlayback::is_end() const { - return current == "End" && fading_from == StringName(); + return current == AnimationNodeStateMachine::END_NODE && fading_from == StringName(); } StringName AnimationNodeStateMachinePlayback::get_current_node() const { @@ -444,7 +447,7 @@ bool AnimationNodeStateMachinePlayback::_travel_children(AnimationTree *p_tree, if (p_test_only) { child_playback = child_playback->duplicate(); } - child_playback->_travel_main("End"); + child_playback->_travel_main(AnimationNodeStateMachine::END_NODE); child_found_route &= child_playback->_travel(p_tree, child_anodesm.ptr(), false, p_test_only); child_path += "/" + child_playback->get_current_node(); } @@ -487,7 +490,7 @@ bool AnimationNodeStateMachinePlayback::_travel_children(AnimationTree *p_tree, void AnimationNodeStateMachinePlayback::_start(AnimationNodeStateMachine *p_state_machine) { playing = true; - _set_current(p_state_machine, start_request != StringName() ? start_request : p_state_machine->start_node); + _set_current(p_state_machine, start_request != StringName() ? start_request : AnimationNodeStateMachine::START_NODE); teleport_request = true; stop_request = false; start_request = StringName(); @@ -504,7 +507,7 @@ String AnimationNodeStateMachinePlayback::_validate_path(AnimationNodeStateMachi String target = p_path; Ref<AnimationNodeStateMachine> anodesm = p_state_machine->find_node_by_path(target); while (anodesm.is_valid() && anodesm->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) { - Vector<int> indices = anodesm->find_transition_from(anodesm->start_node); + Vector<int> indices = anodesm->find_transition_from(AnimationNodeStateMachine::START_NODE); if (indices.size()) { target = target + "/" + anodesm->get_transition_to(indices[0]); // Find next state of Start. } else { @@ -657,7 +660,7 @@ bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree, if (i >= new_path.size()) { break; // Tracing has been finished, needs to break. } - playback->_travel_main("End"); + playback->_travel_main(AnimationNodeStateMachine::END_NODE); if (!playback->_travel(p_tree, anodesm.ptr(), false, p_test_only)) { found_route = false; break; @@ -815,8 +818,8 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St bool is_start_of_group = false; bool is_end_of_group = false; if (!p_state_machine->are_ends_reset() || p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) { - is_start_of_group = fading_from == p_state_machine->start_node; - is_end_of_group = current == p_state_machine->end_node; + is_start_of_group = fading_from == AnimationNodeStateMachine::START_NODE; + is_end_of_group = current == AnimationNodeStateMachine::END_NODE; } // Calc blend amount by cross-fade. @@ -878,24 +881,15 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St } // Find next and see when to transition. - _transition_to_next_recursive(tree, p_state_machine, p_test_only); + bool will_end = _transition_to_next_recursive(tree, p_state_machine, p_test_only) || current == AnimationNodeStateMachine::END_NODE; // Predict remaining time. - if (p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) { + if (will_end || ((p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) && !p_state_machine->has_transition_from(current))) { // There is no next transition. - if (!p_state_machine->has_transition_from(current)) { - if (fading_from != StringName()) { - return current_nti.get_remain() > fadeing_from_nti.get_remain() ? current_nti : fadeing_from_nti; - } - return current_nti; - } - } - - if (current == p_state_machine->end_node) { - if (fading_from != StringName() && fadeing_from_nti.get_remain() > 0) { - return fadeing_from_nti; + if (fading_from != StringName()) { + return current_nti.get_remain() > fadeing_from_nti.get_remain() ? current_nti : fadeing_from_nti; } - return AnimationNode::NodeTimeInfo(); + return current_nti; } if (!is_end()) { @@ -908,8 +902,6 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const St bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only) { _reset_request_for_fading_from = false; - bool is_state_changed = false; - AnimationMixer::PlaybackInfo pi; NextInfo next; Vector<StringName> transition_path; @@ -927,7 +919,6 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT } transition_path.push_back(next.node); - is_state_changed = true; // Setting for fading. if (next.xfade) { @@ -959,6 +950,10 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT _set_current(p_state_machine, next.node); current_curve = next.curve; + if (current == AnimationNodeStateMachine::END_NODE) { + break; + } + _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; @@ -985,7 +980,7 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT } } - return is_state_changed; + return next.node == AnimationNodeStateMachine::END_NODE; } bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, NextInfo p_next, bool p_test_only) { @@ -1019,7 +1014,7 @@ bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p return false; } - if (current != p_state_machine->start_node && p_next.switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_AT_END) { + if (current != AnimationNodeStateMachine::START_NODE && p_next.switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_AT_END) { return current_nti.get_remain(p_next.break_loop_at_end) <= p_next.xfade; } return true; @@ -1029,13 +1024,13 @@ Ref<AnimationNodeStateMachineTransition> AnimationNodeStateMachinePlayback::_che Ref<AnimationNodeStateMachineTransition> temp_transition; Ref<AnimationNodeStateMachinePlayback> parent_playback; if (r_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) { - if (p_transition.from == "Start") { + if (p_transition.from == AnimationNodeStateMachine::START_NODE) { parent_playback = _get_parent_playback(p_tree); if (parent_playback.is_valid()) { r_bypass = true; temp_transition = parent_playback->_get_group_start_transition(); } - } else if (p_transition.to == "End") { + } else if (p_transition.to == AnimationNodeStateMachine::END_NODE) { parent_playback = _get_parent_playback(p_tree); if (parent_playback.is_valid()) { temp_transition = parent_playback->_get_group_end_transition(); @@ -1522,7 +1517,7 @@ void AnimationNodeStateMachine::add_transition(const StringName &p_from, const S return; } - ERR_FAIL_COND(p_from == end_node || p_to == start_node); + ERR_FAIL_COND(p_from == END_NODE || p_to == START_NODE); ERR_FAIL_COND(p_from == p_to); ERR_FAIL_COND(!_can_connect(p_from)); ERR_FAIL_COND(!_can_connect(p_to)); @@ -1564,7 +1559,7 @@ StringName AnimationNodeStateMachine::get_transition_to(int p_transition) const bool AnimationNodeStateMachine::is_transition_across_group(int p_transition) const { ERR_FAIL_INDEX_V(p_transition, transitions.size(), false); if (get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) { - if (transitions[p_transition].from == "Start" || transitions[p_transition].to == "End") { + if (transitions[p_transition].from == START_NODE || transitions[p_transition].to == END_NODE) { return true; } } @@ -1622,6 +1617,7 @@ AnimationNode::NodeTimeInfo AnimationNodeStateMachine::_process(const AnimationM if (p_test_only) { playback_new = playback_new->duplicate(); // Don't process original when testing. } + return playback_new->process(node_state.base_path, this, p_playback_info, p_test_only); } @@ -1741,8 +1737,6 @@ void AnimationNodeStateMachine::reset_state() { states.clear(); transitions.clear(); playback = "playback"; - start_node = "Start"; - end_node = "End"; graph_offset = Vector2(); Ref<AnimationNodeStartState> s; @@ -1750,14 +1744,14 @@ void AnimationNodeStateMachine::reset_state() { State start; start.node = s; start.position = Vector2(200, 100); - states[start_node] = start; + states[START_NODE] = start; Ref<AnimationNodeEndState> e; e.instantiate(); State end; end.node = e; end.position = Vector2(900, 100); - states[end_node] = end; + states[END_NODE] = end; emit_changed(); emit_signal(SNAME("tree_changed")); @@ -1847,17 +1841,20 @@ void AnimationNodeStateMachine::_bind_methods() { } AnimationNodeStateMachine::AnimationNodeStateMachine() { + START_NODE = "Start"; + END_NODE = "End"; + Ref<AnimationNodeStartState> s; s.instantiate(); State start; start.node = s; start.position = Vector2(200, 100); - states[start_node] = start; + states[START_NODE] = start; Ref<AnimationNodeEndState> e; e.instantiate(); State end; end.node = e; end.position = Vector2(900, 100); - states[end_node] = end; + states[END_NODE] = end; } diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index 8078ffb26d..b58ff4d224 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -110,6 +110,9 @@ class AnimationNodeStateMachine : public AnimationRootNode { GDCLASS(AnimationNodeStateMachine, AnimationRootNode); public: + static StringName START_NODE; + static StringName END_NODE; + enum StateMachineType { STATE_MACHINE_TYPE_ROOT, STATE_MACHINE_TYPE_NESTED, @@ -164,9 +167,6 @@ protected: virtual void reset_state() override; public: - StringName start_node = "Start"; - StringName end_node = "End"; - virtual void get_parameter_list(List<PropertyInfo> *r_list) 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; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 5756edaa48..bd8c7ff882 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -158,7 +158,7 @@ void AnimationPlayer::_notification(int p_what) { } } -void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, float p_blend, bool p_seeked, bool p_started, bool p_is_current) { +void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, float p_blend, bool p_seeked, bool p_internal_seeked, bool p_started, bool p_is_current) { double speed = speed_scale * cd.speed_scale; bool backwards = signbit(speed); // Negative zero means playing backwards too. double delta = p_started ? 0 : p_delta * speed; @@ -237,9 +237,8 @@ void AnimationPlayer::_process_playback_data(PlaybackData &cd, double p_delta, f if (Math::is_zero_approx(pi.delta) && backwards) { pi.delta = -0.0; // Sign is needed to handle converted Continuous track from Discrete track correctly. } - // AnimationPlayer doesn't have internal seeking. - // However, immediately after playback, discrete keys should be retrieved with EXACT mode since behind keys must be ignored at that time. - pi.is_external_seeking = !p_started; + // Immediately after playback, discrete keys should be retrieved with EXACT mode since behind keys must be ignored at that time. + pi.is_external_seeking = !p_internal_seeked && !p_started; pi.looped_flag = looped_flag; pi.weight = p_blend; make_animation_instance(cd.from->name, pi); @@ -259,13 +258,15 @@ void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) { Playback &c = playback; bool seeked = c.seeked; // The animation may be changed during process, so it is safer that the state is changed before process. + bool internal_seeked = c.internal_seeked; if (!Math::is_zero_approx(p_delta)) { c.seeked = false; + c.internal_seeked = false; } // Second, process current animation to check if the animation end reached. - _process_playback_data(c.current, p_delta, get_current_blend_amount(), seeked, p_started, true); + _process_playback_data(c.current, p_delta, get_current_blend_amount(), seeked, internal_seeked, p_started, true); // Finally, if not end the animation, do blending. if (end_reached) { @@ -282,7 +283,7 @@ void AnimationPlayer::_blend_playback_data(double p_delta, bool p_started) { } // Note: There may be issues if an animation event triggers an animation change while this blend is active, // so it is best to use "deferred" calls instead of "immediate" for animation events that can trigger new animations. - _process_playback_data(b.data, p_delta, b.blend_left, false, false); + _process_playback_data(b.data, p_delta, b.blend_left, false, false, false); } for (List<Blend>::Element *&E : to_erase) { c.blend.erase(E); @@ -450,10 +451,10 @@ void AnimationPlayer::_play(const StringName &p_name, double p_custom_blend, flo } else { if (p_from_end && c.current.pos == 0) { // Animation reset but played backwards, set position to the end. - seek(c.current.from->animation->get_length(), true, true); + seek_internal(c.current.from->animation->get_length(), true, true, true); } else if (!p_from_end && c.current.pos == c.current.from->animation->get_length()) { // Animation resumed but already ended, set position to the beginning. - seek(0, true, true); + seek_internal(0, true, true, true); } else if (playing) { return; } @@ -579,7 +580,7 @@ float AnimationPlayer::get_playing_speed() const { return speed_scale * playback.current.speed_scale; } -void AnimationPlayer::seek(double p_time, bool p_update, bool p_update_only) { +void AnimationPlayer::seek_internal(double p_time, bool p_update, bool p_update_only, bool p_is_internal_seek) { if (!active) { return; } @@ -600,12 +601,18 @@ void AnimationPlayer::seek(double p_time, bool p_update, bool p_update_only) { } playback.seeked = true; + playback.internal_seeked = p_is_internal_seek; + if (p_update) { _process_animation(is_backward ? -0.0 : 0.0, p_update_only); playback.seeked = false; // If animation was proceeded here, no more seek in internal process. } } +void AnimationPlayer::seek(double p_time, bool p_update, bool p_update_only) { + seek_internal(p_time, p_update, p_update_only); +} + void AnimationPlayer::advance(double p_time) { _check_immediately_after_start(); AnimationMixer::advance(p_time); @@ -661,7 +668,7 @@ void AnimationPlayer::_stop_internal(bool p_reset, bool p_keep_state) { c.current.pos = 0; } else { is_stopping = true; - seek(0, true, true); + seek_internal(0, true, true, true); is_stopping = false; } c.current.from = nullptr; diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 508b2c49fa..e05a2c9935 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -80,6 +80,7 @@ private: PlaybackData current; StringName assigned; bool seeked = false; + bool internal_seeked = false; bool started = false; List<Blend> blend; } playback; @@ -116,7 +117,7 @@ private: void _play(const StringName &p_name, double p_custom_blend = -1, float p_custom_scale = 1.0, bool p_from_end = false); void _capture(const StringName &p_name, bool p_from_end = false, double p_duration = -1.0, Tween::TransitionType p_trans_type = Tween::TRANS_LINEAR, Tween::EaseType p_ease_type = Tween::EASE_IN); - void _process_playback_data(PlaybackData &cd, double p_delta, float p_blend, bool p_seeked, bool p_started, bool p_is_current = false); + void _process_playback_data(PlaybackData &cd, double p_delta, float p_blend, bool p_seeked, bool p_internal_seeked, bool p_started, bool p_is_current = false); void _blend_playback_data(double p_delta, bool p_started); void _stop_internal(bool p_reset, bool p_keep_state); void _check_immediately_after_start(); @@ -200,6 +201,7 @@ public: void set_movie_quit_on_finish_enabled(bool p_enabled); bool is_movie_quit_on_finish_enabled() const; + void seek_internal(double p_time, bool p_update = false, bool p_update_only = false, bool p_is_internal_seek = false); void seek(double p_time, bool p_update = false, bool p_update_only = false); double get_current_animation_position() const; |