Add indicator for state machine transition fade progress and position of state transitioning from.

This commit is contained in:
SaracenOne 2022-10-21 18:35:25 +01:00
parent 4368191a9f
commit 02a82c9531
4 changed files with 125 additions and 27 deletions

View File

@ -1127,7 +1127,7 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
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, 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_multi_transitions) {
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"));
@ -1153,11 +1153,15 @@ void AnimationNodeStateMachineEditor::_connection_draw(const Vector2 &p_from, co
if (p_travel) { if (p_travel) {
linecolor = accent; linecolor = accent;
linecolor.set_hsv(1.0, linecolor.get_s(), linecolor.get_v());
} }
state_machine_draw->draw_line(p_from, p_to, linecolor, 2); state_machine_draw->draw_line(p_from, p_to, linecolor, 2);
if (p_fade_ratio > 0.0) {
Color fade_linecolor = accent;
fade_linecolor.set_hsv(1.0, fade_linecolor.get_s(), fade_linecolor.get_v());
state_machine_draw->draw_line(p_from, p_from.lerp(p_to, p_fade_ratio), fade_linecolor, 2);
}
Ref<Texture2D> icon = icons[p_mode + (p_auto_advance ? 3 : 0)]; Ref<Texture2D> icon = icons[p_mode + (p_auto_advance ? 3 : 0)];
Transform2D xf; Transform2D xf;
@ -1327,7 +1331,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
} }
} }
_connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()), true, false, false, false, false); _connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()), true, false, false, 0.0, false, false);
} }
Ref<Texture2D> tr_reference_icon = get_theme_icon(SNAME("TransitionImmediateBig"), SNAME("EditorIcons")); Ref<Texture2D> tr_reference_icon = get_theme_icon(SNAME("TransitionImmediateBig"), SNAME("EditorIcons"));
@ -1357,6 +1361,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
tl.mode = tr->get_switch_mode(); tl.mode = tr->get_switch_mode();
tl.width = tr_bidi_offset; tl.width = tr_bidi_offset;
tl.travel = false; tl.travel = false;
tl.fade_ratio = 0.0;
tl.hidden = false; tl.hidden = false;
if (state_machine->has_local_transition(local_to, local_from)) { //offset if same exists if (state_machine->has_local_transition(local_to, local_from)) { //offset if same exists
@ -1378,6 +1383,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
if (blend_from == local_from && current == local_to) { if (blend_from == local_from && current == local_to) {
tl.travel = true; tl.travel = true;
tl.fade_ratio = MIN(1.0, fading_pos / fading_time);
} }
if (travel_path.size()) { if (travel_path.size()) {
@ -1418,7 +1424,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.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.multi_transitions.is_empty());
} }
} }
@ -1508,25 +1514,24 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
state_machine_play_pos->queue_redraw(); state_machine_play_pos->queue_redraw();
} }
void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(String p_name, float p_ratio) {
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"); Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
if (!playback.is_valid() || !playback->is_playing()) { if (!playback.is_valid() || !playback->is_playing()) {
return; return;
} }
if (playback->get_current_node() == state_machine->start_node || playback->get_current_node() == state_machine->end_node) { if (p_name == state_machine->start_node || p_name == state_machine->end_node || p_name.is_empty()) {
return; return;
} }
int idx = -1; int idx = -1;
for (int i = 0; i < node_rects.size(); i++) { for (int i = 0; i < node_rects.size(); i++) {
if (node_rects[i].node_name == playback->get_current_node()) { if (node_rects[i].node_name == p_name) {
idx = i; idx = i;
break; break;
} }
@ -1550,10 +1555,7 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
} }
to.y = from.y; to.y = from.y;
float len = MAX(0.0001, current_length); float c = p_ratio;
float pos = CLAMP(play_pos, 0, len);
float c = pos / len;
Color fg = get_theme_color(SNAME("font_color"), SNAME("Label")); Color fg = get_theme_color(SNAME("font_color"), SNAME("Label"));
Color bg = fg; Color bg = fg;
bg.a *= 0.3; bg.a *= 0.3;
@ -1565,6 +1567,32 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw() {
state_machine_play_pos->draw_line(from, to, fg, 2); state_machine_play_pos->draw_line(from, to, fg, 2);
} }
void AnimationNodeStateMachineEditor::_state_machine_pos_draw_all() {
AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
if (!tree) {
return;
}
Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
if (!playback.is_valid() || !playback->is_playing()) {
return;
}
{
float len = MAX(0.0001, current_length);
float pos = CLAMP(current_play_pos, 0, len);
float c = pos / len;
_state_machine_pos_draw_individual(playback->get_current_node(), c);
}
{
float len = MAX(0.0001, fade_from_length);
float pos = CLAMP(fade_from_current_play_pos, 0, len);
float c = pos / len;
_state_machine_pos_draw_individual(playback->get_fading_from_node(), c);
}
}
void AnimationNodeStateMachineEditor::_update_graph() { void AnimationNodeStateMachineEditor::_update_graph() {
if (updating) { if (updating) {
return; return;
@ -1687,17 +1715,28 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
Vector<StringName> tp; Vector<StringName> tp;
bool is_playing = false; bool is_playing = false;
StringName current_node; StringName current_node;
StringName blend_from_node; StringName fading_from_node;
play_pos = 0;
current_play_pos = 0;
current_length = 0; current_length = 0;
fade_from_current_play_pos = 0;
fade_from_length = 0;
fading_time = 0;
fading_pos = 0;
if (playback.is_valid()) { if (playback.is_valid()) {
tp = playback->get_travel_path(); tp = playback->get_travel_path();
is_playing = playback->is_playing(); is_playing = playback->is_playing();
current_node = playback->get_current_node(); current_node = playback->get_current_node();
blend_from_node = playback->get_fading_from_node(); fading_from_node = playback->get_fading_from_node();
play_pos = playback->get_current_play_pos(); current_play_pos = playback->get_current_play_pos();
current_length = playback->get_current_length(); current_length = playback->get_current_length();
fade_from_current_play_pos = playback->get_fade_from_play_pos();
fade_from_length = playback->get_fade_from_length();
fading_time = playback->get_fading_time();
fading_pos = playback->get_fading_pos();
} }
{ {
@ -1714,12 +1753,19 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
} }
//redraw if travel state changed //redraw if travel state changed
if (!same_travel_path || last_active != is_playing || last_current_node != current_node || last_blend_from_node != blend_from_node) { if (!same_travel_path ||
last_active != is_playing ||
last_current_node != current_node ||
last_fading_from_node != fading_from_node ||
last_fading_time != fading_time ||
last_fading_pos != fading_pos) {
state_machine_draw->queue_redraw(); state_machine_draw->queue_redraw();
last_travel_path = tp; last_travel_path = tp;
last_current_node = current_node; last_current_node = current_node;
last_active = is_playing; last_active = is_playing;
last_blend_from_node = blend_from_node; last_fading_from_node = fading_from_node;
last_fading_time = fading_time;
last_fading_pos = fading_pos;
state_machine_play_pos->queue_redraw(); state_machine_play_pos->queue_redraw();
} }
@ -1737,14 +1783,15 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
// 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
if (current_node_playback.is_valid()) { if (current_node_playback.is_valid()) {
play_pos = current_node_playback->get_current_play_pos(); current_play_pos = current_node_playback->get_current_play_pos();
current_length = current_node_playback->get_current_length(); current_length = current_node_playback->get_current_length();
} }
} }
} }
if (last_play_pos != play_pos) { if (last_play_pos != current_play_pos || fade_from_last_play_pos != fade_from_current_play_pos) {
last_play_pos = play_pos; last_play_pos = current_play_pos;
fade_from_last_play_pos = fade_from_current_play_pos;
state_machine_play_pos->queue_redraw(); state_machine_play_pos->queue_redraw();
} }
} break; } break;
@ -2048,7 +2095,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
state_machine_draw->add_child(state_machine_play_pos); state_machine_draw->add_child(state_machine_play_pos);
state_machine_play_pos->set_mouse_filter(MOUSE_FILTER_PASS); //pass all to parent state_machine_play_pos->set_mouse_filter(MOUSE_FILTER_PASS); //pass all to parent
state_machine_play_pos->set_anchors_and_offsets_preset(PRESET_FULL_RECT); state_machine_play_pos->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
state_machine_play_pos->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_pos_draw)); state_machine_play_pos->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_state_machine_pos_draw_all));
v_scroll = memnew(VScrollBar); v_scroll = memnew(VScrollBar);
state_machine_draw->add_child(v_scroll); state_machine_draw->add_child(v_scroll);

View File

@ -85,9 +85,12 @@ 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, 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_multi_transitions);
void _state_machine_draw(); void _state_machine_draw();
void _state_machine_pos_draw();
void _state_machine_pos_draw_individual(String p_name, float p_ratio);
void _state_machine_pos_draw_all();
void _update_graph(); void _update_graph();
@ -150,6 +153,7 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
float width = 0; float width = 0;
bool selected; bool selected;
bool travel; bool travel;
float fade_ratio;
bool hidden; bool hidden;
int transition_index; int transition_index;
Vector<TransitionLine> multi_transitions; Vector<TransitionLine> multi_transitions;
@ -204,13 +208,23 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
void _delete_tree_draw(); void _delete_tree_draw();
bool last_active = false; bool last_active = false;
StringName last_blend_from_node; StringName last_fading_from_node;
StringName last_current_node; StringName last_current_node;
Vector<StringName> last_travel_path; Vector<StringName> last_travel_path;
float fade_from_last_play_pos = 0.0f;
float fade_from_current_play_pos = 0.0f;
float fade_from_length = 0.0f;
float last_play_pos = 0.0f; float last_play_pos = 0.0f;
float play_pos = 0.0f; float current_play_pos = 0.0f;
float current_length = 0.0f; float current_length = 0.0f;
float last_fading_time = 0.0f;
float last_fading_pos = 0.0f;
float fading_time = 0.0f;
float fading_pos = 0.0f;
float error_time = 0.0f; float error_time = 0.0f;
String error_text; String error_text;

View File

@ -228,6 +228,22 @@ float AnimationNodeStateMachinePlayback::get_current_length() const {
return len_current; return len_current;
} }
float AnimationNodeStateMachinePlayback::get_fade_from_play_pos() const {
return pos_fade_from;
}
float AnimationNodeStateMachinePlayback::get_fade_from_length() const {
return len_fade_from;
}
float AnimationNodeStateMachinePlayback::get_fading_time() const {
return fading_time;
}
float AnimationNodeStateMachinePlayback::get_fading_pos() const {
return fading_pos;
}
bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel) { bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel) {
ERR_FAIL_COND_V(!playing, false); ERR_FAIL_COND_V(!playing, false);
ERR_FAIL_COND_V(!p_state_machine->states.has(p_travel), false); ERR_FAIL_COND_V(!p_state_machine->states.has(p_travel), false);
@ -466,7 +482,17 @@ double AnimationNodeStateMachinePlayback::_process(AnimationNodeStateMachine *p_
if (fading_from != StringName()) { if (fading_from != StringName()) {
double fade_blend_inv = 1.0 - fade_blend; double fade_blend_inv = 1.0 - fade_blend;
p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend_inv) ? CMP_EPSILON : fade_blend_inv, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. float fading_from_rem = 0.0;
fading_from_rem = p_state_machine->blend_node(fading_from, p_state_machine->states[fading_from].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend_inv) ? CMP_EPSILON : fade_blend_inv, AnimationNode::FILTER_IGNORE, true); // 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;
}
{ //advance and loop check
float next_pos = len_fade_from - fading_from_rem;
pos_fade_from = next_pos; //looped
}
if (fade_blend >= 1.0) { if (fade_blend >= 1.0) {
fading_from = StringName(); fading_from = StringName();
} }
@ -633,6 +659,8 @@ double AnimationNodeStateMachinePlayback::_process(AnimationNodeStateMachine *p_
} }
current = next; current = next;
pos_fade_from = pos_current;
len_fade_from = len_current;
if (reset_request) { 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. 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.

View File

@ -118,6 +118,9 @@ class AnimationNodeStateMachinePlayback : public Resource {
StringName next; StringName next;
}; };
double len_fade_from = 0.0;
double pos_fade_from = 0.0;
double len_current = 0.0; double len_current = 0.0;
double pos_current = 0.0; double pos_current = 0.0;
bool end_loop = false; bool end_loop = false;
@ -164,6 +167,12 @@ public:
float get_current_play_pos() const; float get_current_play_pos() const;
float get_current_length() 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(); AnimationNodeStateMachinePlayback();
}; };