Преглед изворни кода

Merge pull request #82210 from YuriSizov/editor-animation-uiux-cleanup

Fix theme access and improve UX in AnimationTree editor
Rémi Verschelde пре 1 година
родитељ
комит
37d5e1e0e3

+ 49 - 13
editor/editor_themes.cpp

@@ -2014,17 +2014,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	graphn_sb_titlebar_selected->set_expand_margin(SIDE_TOP, 2 * EDSCALE);
 	Ref<StyleBoxEmpty> graphn_sb_slot = make_empty_stylebox(12, 0, 12, 0);
 
-	// StateMachine.
-	const int sm_margin_side = 10;
-	Ref<StyleBoxFlat> smgraphsb = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), sm_margin_side, 24, sm_margin_side, gn_margin_bottom, corner_width);
-	smgraphsb->set_border_width_all(border_width);
-	smgraphsb->set_border_color(graphnode_bg);
-	Ref<StyleBoxFlat> smgraphsbselected = make_flat_stylebox(graphnode_bg * Color(1, 1, 1, 0.9), sm_margin_side, 24, sm_margin_side, gn_margin_bottom, corner_width);
-	smgraphsbselected->set_border_width_all(2 * EDSCALE + border_width);
-	smgraphsbselected->set_border_color(Color(accent_color.r, accent_color.g, accent_color.b, 0.9));
-	smgraphsbselected->set_shadow_size(8 * EDSCALE);
-	smgraphsbselected->set_shadow_color(shadow_color);
-
 	theme->set_stylebox("panel", "GraphElement", graphn_sb_panel);
 	theme->set_stylebox("panel_selected", "GraphElement", graphn_sb_panel_selected);
 	theme->set_stylebox("titlebar", "GraphElement", graphn_sb_titlebar);
@@ -2059,8 +2048,55 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
 	port_icon->set_size_override(Size2(12, 12));
 	theme->set_icon("port", "GraphNode", port_icon);
 
-	theme->set_stylebox("state_machine_frame", "GraphNode", smgraphsb);
-	theme->set_stylebox("state_machine_selected_frame", "GraphNode", smgraphsbselected);
+	// StateMachine graph
+	theme->set_stylebox("panel", "GraphStateMachine", style_tree_bg);
+	theme->set_stylebox("error_panel", "GraphStateMachine", style_tree_bg);
+	theme->set_color("error_color", "GraphStateMachine", error_color);
+
+	const int sm_margin_side = 10 * EDSCALE;
+
+	Ref<StyleBoxFlat> sm_node_style = make_flat_stylebox(dark_color_3 * Color(1, 1, 1, 0.7), sm_margin_side, 24 * EDSCALE, sm_margin_side, gn_margin_bottom, corner_width);
+	sm_node_style->set_border_width_all(border_width);
+	sm_node_style->set_border_color(graphnode_bg);
+
+	Ref<StyleBoxFlat> sm_node_selected_style = make_flat_stylebox(graphnode_bg * Color(1, 1, 1, 0.9), sm_margin_side, 24 * EDSCALE, sm_margin_side, gn_margin_bottom, corner_width);
+	sm_node_selected_style->set_border_width_all(2 * EDSCALE + border_width);
+	sm_node_selected_style->set_border_color(accent_color * Color(1, 1, 1, 0.9));
+	sm_node_selected_style->set_shadow_size(8 * EDSCALE);
+	sm_node_selected_style->set_shadow_color(shadow_color);
+
+	Ref<StyleBoxFlat> sm_node_playing_style = sm_node_selected_style->duplicate();
+	sm_node_playing_style->set_border_color(warning_color);
+	sm_node_playing_style->set_shadow_color(warning_color * Color(1, 1, 1, 0.2));
+
+	theme->set_stylebox("node_frame", "GraphStateMachine", sm_node_style);
+	theme->set_stylebox("node_frame_selected", "GraphStateMachine", sm_node_selected_style);
+	theme->set_stylebox("node_frame_playing", "GraphStateMachine", sm_node_playing_style);
+
+	Ref<StyleBoxFlat> sm_node_start_style = sm_node_style->duplicate();
+	sm_node_start_style->set_border_width_all(1 * EDSCALE);
+	sm_node_start_style->set_border_color(success_color.lightened(0.24));
+	theme->set_stylebox("node_frame_start", "GraphStateMachine", sm_node_start_style);
+
+	Ref<StyleBoxFlat> sm_node_end_style = sm_node_style->duplicate();
+	sm_node_end_style->set_border_width_all(1 * EDSCALE);
+	sm_node_end_style->set_border_color(error_color);
+	theme->set_stylebox("node_frame_end", "GraphStateMachine", sm_node_end_style);
+
+	theme->set_font("node_title_font", "GraphStateMachine", theme->get_font(SNAME("font"), SNAME("Label")));
+	theme->set_font_size("node_title_font_size", "GraphStateMachine", theme->get_font_size(SNAME("font_size"), SNAME("Label")));
+	theme->set_color("node_title_font_color", "GraphStateMachine", font_color);
+
+	theme->set_color("transition_color", "GraphStateMachine", font_color);
+	theme->set_color("transition_disabled_color", "GraphStateMachine", font_color * Color(1, 1, 1, 0.2));
+	theme->set_color("transition_icon_color", "GraphStateMachine", Color(1, 1, 1));
+	theme->set_color("transition_icon_disabled_color", "GraphStateMachine", Color(1, 1, 1, 0.2));
+	theme->set_color("highlight_color", "GraphStateMachine", accent_color);
+	theme->set_color("highlight_disabled_color", "GraphStateMachine", accent_color * Color(1, 1, 1, 0.6));
+	theme->set_color("guideline_color", "GraphStateMachine", font_color * Color(1, 1, 1, 0.3));
+
+	theme->set_color("playback_color", "GraphStateMachine", font_color);
+	theme->set_color("playback_background_color", "GraphStateMachine", font_color * Color(1, 1, 1, 0.3));
 
 	// GridContainer
 	theme->set_constant("v_separation", "GridContainer", Math::round(widget_default_margin.y - 2 * EDSCALE));

+ 5 - 10
editor/gui/scene_tree_editor.cpp

@@ -1564,14 +1564,6 @@ void SceneTreeDialog::set_valid_types(const Vector<StringName> &p_valid) {
 	show_all_nodes->show();
 }
 
-void SceneTreeDialog::_update_theme() {
-	filter->set_right_icon(tree->get_editor_theme_icon(SNAME("Search")));
-	for (TextureRect *trect : valid_type_icons) {
-		trect->set_custom_minimum_size(Vector2(get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)), 0));
-		trect->set_texture(EditorNode::get_singleton()->get_class_icon(trect->get_meta("type")));
-	}
-}
-
 void SceneTreeDialog::_notification(int p_what) {
 	switch (p_what) {
 		case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -1585,11 +1577,14 @@ void SceneTreeDialog::_notification(int p_what) {
 
 		case NOTIFICATION_ENTER_TREE: {
 			connect("confirmed", callable_mp(this, &SceneTreeDialog::_select));
-			_update_theme();
 		} break;
 
 		case NOTIFICATION_THEME_CHANGED: {
-			_update_theme();
+			filter->set_right_icon(get_editor_theme_icon(SNAME("Search")));
+			for (TextureRect *trect : valid_type_icons) {
+				trect->set_custom_minimum_size(Vector2(get_theme_constant(SNAME("class_icon_size"), EditorStringName(Editor)), 0));
+				trect->set_texture(EditorNode::get_singleton()->get_class_icon(trect->get_meta("type")));
+			}
 		} break;
 
 		case NOTIFICATION_EXIT_TREE: {

+ 0 - 1
editor/gui/scene_tree_editor.h

@@ -188,7 +188,6 @@ class SceneTreeDialog : public ConfirmationDialog {
 	void _selected_changed();
 	void _filter_changed(const String &p_filter);
 	void _show_all_nodes_changed(bool p_button_pressed);
-	void _update_theme();
 
 protected:
 	void _notification(int p_what);

+ 4 - 8
editor/plugins/animation_blend_tree_editor_plugin.cpp

@@ -263,7 +263,8 @@ void AnimationNodeBlendTreeEditor::update_graph() {
 			mb->get_popup()->connect("index_pressed", callable_mp(this, &AnimationNodeBlendTreeEditor::_anim_selected).bind(options, E), CONNECT_DEFERRED);
 		}
 
-		Ref<StyleBoxFlat> sb = node->get_theme_stylebox(SNAME("panel"), SNAME("GraphNode"));
+		// TODO: Avoid using strings, expose a method on GraphNode instead.
+		Ref<StyleBoxFlat> sb = node->get_theme_stylebox(SNAME("panel"));
 		Color c = sb->get_border_color();
 		Color mono_color = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0) : Color(0.0, 0.0, 0.0);
 		mono_color.a = 0.85;
@@ -831,16 +832,10 @@ void AnimationNodeBlendTreeEditor::_update_editor_settings() {
 	graph->set_warped_panning(bool(EDITOR_GET("editors/panning/warped_mouse_panning")));
 }
 
-void AnimationNodeBlendTreeEditor::_update_theme() {
-	error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
-	error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
-}
-
 void AnimationNodeBlendTreeEditor::_notification(int p_what) {
 	switch (p_what) {
 		case NOTIFICATION_ENTER_TREE: {
 			_update_editor_settings();
-			_update_theme();
 		} break;
 
 		case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
@@ -848,7 +843,8 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
 		} break;
 
 		case NOTIFICATION_THEME_CHANGED: {
-			_update_theme();
+			error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
+			error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
 
 			if (is_visible_in_tree()) {
 				update_graph();

+ 0 - 1
editor/plugins/animation_blend_tree_editor_plugin.h

@@ -127,7 +127,6 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
 	void _property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing);
 
 	void _update_editor_settings();
-	void _update_theme();
 
 	EditorFileDialog *open_file = nullptr;
 	Ref<AnimationNode> file_loaded;

+ 170 - 155
editor/plugins/animation_state_machine_editor.cpp

@@ -38,7 +38,6 @@
 #include "editor/editor_node.h"
 #include "editor/editor_scale.h"
 #include "editor/editor_settings.h"
-#include "editor/editor_string_names.h"
 #include "editor/editor_undo_redo_manager.h"
 #include "editor/gui/editor_file_dialog.h"
 #include "scene/animation/animation_blend_tree.h"
@@ -53,6 +52,7 @@
 #include "scene/main/window.h"
 #include "scene/resources/style_box_flat.h"
 #include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
 
 bool AnimationNodeStateMachineEditor::can_edit(const Ref<AnimationNode> &p_node) {
 	Ref<AnimationNodeStateMachine> ansm = p_node;
@@ -179,8 +179,8 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
 
 			if (!read_only) {
 				if (node_rects[i].name.has_point(mb->get_position()) && state_machine->can_edit_node(node_rects[i].node_name)) { // edit name
-					Ref<StyleBox> line_sb = get_theme_stylebox(SNAME("normal"), SNAME("LineEdit"));
-
+					// TODO: Avoid using strings, expose a method on LineEdit.
+					Ref<StyleBox> line_sb = name_edit->get_theme_stylebox(SNAME("normal"));
 					Rect2 edit_rect = node_rects[i].name;
 					edit_rect.position -= line_sb->get_offset();
 					edit_rect.size += line_sb->get_minimum_size();
@@ -447,8 +447,8 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
 	if (mm.is_valid()) {
 		state_machine_draw->grab_focus();
 
-		String new_over_node;
-		int new_over_node_what = -1;
+		String new_hovered_node_name;
+		HoveredNodeArea new_hovered_node_area = HOVER_NODE_NONE;
 		if (tool_select->is_pressed()) {
 			for (int i = node_rects.size() - 1; i >= 0; i--) { // Inverse to draw order.
 
@@ -457,20 +457,20 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
 				}
 
 				if (node_rects[i].node.has_point(mm->get_position())) {
-					new_over_node = node_rects[i].node_name;
+					new_hovered_node_name = node_rects[i].node_name;
 					if (node_rects[i].play.has_point(mm->get_position())) {
-						new_over_node_what = 0;
+						new_hovered_node_area = HOVER_NODE_PLAY;
 					} else if (node_rects[i].edit.has_point(mm->get_position())) {
-						new_over_node_what = 1;
+						new_hovered_node_area = HOVER_NODE_EDIT;
 					}
 					break;
 				}
 			}
 		}
 
-		if (new_over_node != over_node || new_over_node_what != over_node_what) {
-			over_node = new_over_node;
-			over_node_what = new_over_node_what;
+		if (new_hovered_node_name != hovered_node_name || new_hovered_node_area != hovered_node_area) {
+			hovered_node_name = new_hovered_node_name;
+			hovered_node_area = new_hovered_node_area;
 			state_machine_draw->queue_redraw();
 		}
 
@@ -534,6 +534,23 @@ Control::CursorShape AnimationNodeStateMachineEditor::get_cursor_shape(const Poi
 	return cursor_shape;
 }
 
+String AnimationNodeStateMachineEditor::get_tooltip(const Point2 &p_pos) const {
+	if (hovered_node_name == StringName()) {
+		return AnimationTreeNodeEditorPlugin::get_tooltip(p_pos);
+	}
+
+	String tooltip_text;
+	if (hovered_node_area == HOVER_NODE_PLAY) {
+		tooltip_text = vformat(TTR("Play/Travel to %s"), hovered_node_name);
+	} else if (hovered_node_area == HOVER_NODE_EDIT) {
+		tooltip_text = vformat(TTR("Edit %s"), hovered_node_name);
+	} else {
+		tooltip_text = hovered_node_name;
+	}
+
+	return tooltip_text;
+}
+
 void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) {
 	AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree();
 	if (!tree) {
@@ -543,24 +560,29 @@ void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) {
 	menu->clear();
 	animations_menu->clear();
 	animations_to_add.clear();
-	List<StringName> classes;
-	classes.sort_custom<StringName::AlphCompare>();
-
-	ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
-	menu->add_submenu_item(TTR("Add Animation"), "animations");
 
+	List<StringName> animation_names;
 	if (tree->has_node(tree->get_animation_player())) {
 		AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player()));
 		if (ap) {
-			List<StringName> names;
-			ap->get_animation_list(&names);
-			for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
-				animations_menu->add_icon_item(get_editor_theme_icon("Animation"), E->get());
-				animations_to_add.push_back(E->get());
-			}
+			ap->get_animation_list(&animation_names);
 		}
 	}
 
+	menu->add_submenu_item(TTR("Add Animation"), "animations");
+	if (animation_names.is_empty()) {
+		menu->set_item_disabled(menu->get_item_idx_from_text(TTR("Add Animation")), true);
+	} else {
+		for (const StringName &name : animation_names) {
+			animations_menu->add_icon_item(theme_cache.animation_icon, name);
+			animations_to_add.push_back(name);
+		}
+	}
+
+	List<StringName> classes;
+	ClassDB::get_inheriters_from_class("AnimationRootNode", &classes);
+	classes.sort_custom<StringName::AlphCompare>();
+
 	for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
 		String name = String(E->get()).replace_first("AnimationNode", "");
 		if (name == "Animation" || name == "StartState" || name == "EndState") {
@@ -823,44 +845,29 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
 }
 
 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_is_across_group) {
-	Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label"));
-	Color icon_color(1, 1, 1);
-	Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
-
-	if (!p_enabled) {
-		linecolor.a *= 0.2;
-		icon_color.a *= 0.2;
-		accent.a *= 0.6;
-	}
-
-	const Ref<Texture2D> icons[] = {
-		get_editor_theme_icon(SNAME("TransitionImmediateBig")),
-		get_editor_theme_icon(SNAME("TransitionSyncBig")),
-		get_editor_theme_icon(SNAME("TransitionEndBig")),
-		get_editor_theme_icon(SNAME("TransitionImmediateAutoBig")),
-		get_editor_theme_icon(SNAME("TransitionSyncAutoBig")),
-		get_editor_theme_icon(SNAME("TransitionEndAutoBig"))
-	};
-	const int ICON_COUNT = sizeof(icons) / sizeof(*icons);
-
-	if (p_selected) {
-		state_machine_draw->draw_line(p_from, p_to, accent, 6);
-	}
+	Color line_color = p_enabled ? theme_cache.transition_color : theme_cache.transition_disabled_color;
+	Color icon_color = p_enabled ? theme_cache.transition_icon_color : theme_cache.transition_icon_disabled_color;
+	Color highlight_color = p_enabled ? theme_cache.highlight_color : theme_cache.highlight_disabled_color;
 
 	if (p_travel) {
-		linecolor = accent;
+		line_color = highlight_color;
 	}
 
-	state_machine_draw->draw_line(p_from, p_to, linecolor, 2);
+	if (p_selected) {
+		state_machine_draw->draw_line(p_from, p_to, highlight_color, 6, true);
+	}
+	state_machine_draw->draw_line(p_from, p_to, line_color, 2, true);
 
 	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);
+		Color fade_line_color = highlight_color;
+		fade_line_color.set_hsv(1.0, fade_line_color.get_s(), fade_line_color.get_v());
+		state_machine_draw->draw_line(p_from, p_from.lerp(p_to, p_fade_ratio), fade_line_color, 2);
 	}
+
+	const int ICON_COUNT = sizeof(theme_cache.transition_icons) / sizeof(*theme_cache.transition_icons);
 	int icon_index = p_mode + (p_auto_advance ? ICON_COUNT / 2 : 0);
 	ERR_FAIL_COND(icon_index >= ICON_COUNT);
-	Ref<Texture2D> icon = icons[icon_index];
+	Ref<Texture2D> icon = theme_cache.transition_icons[icon_index];
 
 	Transform2D xf;
 	xf.columns[0] = (p_to - p_from).normalized();
@@ -904,34 +911,12 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
 		return;
 	}
 
-	Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
-
-	Ref<StyleBoxFlat> style = get_theme_stylebox(SNAME("state_machine_frame"), SNAME("GraphNode"));
-	Ref<StyleBoxFlat> style_selected = get_theme_stylebox(SNAME("state_machine_selected_frame"), SNAME("GraphNode"));
-
-	Ref<Font> font = get_theme_font(SNAME("title_font"), SNAME("GraphNode"));
-	int font_size = get_theme_font_size(SNAME("title_font_size"), SNAME("GraphNode"));
-	Color font_color = get_theme_color(SNAME("title_color"), SNAME("GraphNode"));
-	Ref<Texture2D> play = get_editor_theme_icon(SNAME("Play"));
-	Ref<Texture2D> edit = get_editor_theme_icon(SNAME("Edit"));
-	Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
-	Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label"));
-	linecolor.a *= 0.3;
-	Ref<StyleBox> playing_overlay = get_theme_stylebox(SNAME("position"), SNAME("GraphNode"));
-
-	Ref<StyleBoxFlat> start_overlay = style->duplicate();
-	start_overlay->set_border_width_all(1 * EDSCALE);
-	start_overlay->set_border_color(Color::html("#80f6cf"));
-
-	Ref<StyleBoxFlat> end_overlay = style->duplicate();
-	end_overlay->set_border_width_all(1 * EDSCALE);
-	end_overlay->set_border_color(Color::html("#f26661"));
-
 	bool playing = false;
 	StringName current;
 	StringName blend_from;
 	Vector<StringName> travel_path;
 
+	Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback");
 	if (playback.is_valid()) {
 		playing = playback->is_playing();
 		current = playback->get_current_node();
@@ -940,7 +925,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
 	}
 
 	if (state_machine_draw->has_focus()) {
-		state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), accent, false);
+		state_machine_draw->draw_rect(Rect2(Point2(), state_machine_draw->get_size()), theme_cache.highlight_color, false);
 	}
 	int sep = 3 * EDSCALE;
 
@@ -955,29 +940,30 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
 		Vector2 from = (state_machine->get_node_position(selected_node) * EDSCALE) + drag_ofs - state_machine->get_graph_offset() * EDSCALE;
 		if (snap_x != StringName()) {
 			Vector2 to = (state_machine->get_node_position(snap_x) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
-			state_machine_draw->draw_line(from, to, linecolor, 2);
+			state_machine_draw->draw_line(from, to, theme_cache.guideline_color, 2);
 		}
 		if (snap_y != StringName()) {
 			Vector2 to = (state_machine->get_node_position(snap_y) * EDSCALE) - state_machine->get_graph_offset() * EDSCALE;
-			state_machine_draw->draw_line(from, to, linecolor, 2);
+			state_machine_draw->draw_line(from, to, theme_cache.guideline_color, 2);
 		}
 	}
 
 	//pre pass nodes so we know the rectangles
 	for (const StringName &E : nodes) {
-		Ref<AnimationNode> anode = state_machine->get_node(E);
 		String name = E;
+		int name_string_size = theme_cache.node_title_font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.node_title_font_size).width;
+
+		Ref<AnimationNode> anode = state_machine->get_node(name);
 		bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode);
-		Ref<StyleBox> sb = selected_nodes.has(E) ? style_selected : style;
+		bool is_selected = selected_nodes.has(name);
 
-		Size2 s = sb->get_minimum_size();
-		int strsize = font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width;
-		s.width += strsize;
-		s.height += MAX(font->get_height(font_size), play->get_height());
-		s.width += sep + play->get_width();
+		Size2 s = (is_selected ? theme_cache.node_frame_selected : theme_cache.node_frame)->get_minimum_size();
+		s.width += name_string_size;
+		s.height += MAX(theme_cache.node_title_font->get_height(theme_cache.node_title_font_size), theme_cache.play_node->get_height());
+		s.width += sep + theme_cache.play_node->get_width();
 
 		if (needs_editor) {
-			s.width += sep + edit->get_width();
+			s.width += sep + theme_cache.edit_node->get_width();
 		}
 
 		Vector2 offset;
@@ -1028,8 +1014,8 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
 		_connection_draw(from, to, AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()), true, false, false, 0.0, false, false);
 	}
 
-	Ref<Texture2D> tr_reference_icon = get_editor_theme_icon(SNAME("TransitionImmediateBig"));
-	float tr_bidi_offset = int(tr_reference_icon->get_height() * 0.8);
+	// TransitionImmediateBig
+	float tr_bidi_offset = int(theme_cache.transition_icons[0]->get_height() * 0.8);
 
 	//draw transition lines
 	for (int i = 0; i < state_machine->get_transition_count(); i++) {
@@ -1117,62 +1103,60 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() {
 	//draw actual nodes
 	for (int i = 0; i < node_rects.size(); i++) {
 		String name = node_rects[i].node_name;
+		int name_string_size = theme_cache.node_title_font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.node_title_font_size).width;
+
 		Ref<AnimationNode> anode = state_machine->get_node(name);
 		bool needs_editor = AnimationTreeEditor::get_singleton()->can_edit(anode);
-		Ref<StyleBox> sb = selected_nodes.has(name) ? style_selected : style;
-		int strsize = font->get_string_size(name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width;
-		NodeRect &nr = node_rects.write[i];
+		bool is_selected = selected_nodes.has(name);
 
+		NodeRect &nr = node_rects.write[i];
 		Vector2 offset = nr.node.position;
 		int h = nr.node.size.height;
 
 		//prepre rect
 
 		//now scroll it to draw
-		state_machine_draw->draw_style_box(sb, nr.node);
+		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 (state_machine->start_node == name) {
-			state_machine_draw->draw_style_box(sb == style_selected ? style_selected : start_overlay, nr.node);
+		if (!is_selected && state_machine->start_node == name) {
+			state_machine_draw->draw_style_box(theme_cache.node_frame_start, nr.node);
 		}
-
-		if (state_machine->end_node == name) {
-			state_machine_draw->draw_style_box(sb == style_selected ? style_selected : end_overlay, nr.node);
+		if (!is_selected && state_machine->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))) {
-			state_machine_draw->draw_style_box(playing_overlay, nr.node);
+			state_machine_draw->draw_style_box(theme_cache.node_frame_playing, nr.node);
 		}
 
-		offset.x += sb->get_offset().x;
+		offset.x += node_frame_style->get_offset().x;
 
-		nr.play.position = offset + Vector2(0, (h - play->get_height()) / 2).floor();
-		nr.play.size = play->get_size();
+		nr.play.position = offset + Vector2(0, (h - theme_cache.play_node->get_height()) / 2).floor();
+		nr.play.size = theme_cache.play_node->get_size();
 
-		Ref<Texture2D> play_tex = play;
-
-		if (over_node == name && over_node_what == 0) {
-			state_machine_draw->draw_texture(play_tex, nr.play.position, accent);
+		if (hovered_node_name == name && hovered_node_area == HOVER_NODE_PLAY) {
+			state_machine_draw->draw_texture(theme_cache.play_node, nr.play.position, theme_cache.highlight_color);
 		} else {
-			state_machine_draw->draw_texture(play_tex, nr.play.position);
+			state_machine_draw->draw_texture(theme_cache.play_node, nr.play.position);
 		}
 
-		offset.x += sep + play->get_width();
+		offset.x += sep + theme_cache.play_node->get_width();
 
-		nr.name.position = offset + Vector2(0, (h - font->get_height(font_size)) / 2).floor();
-		nr.name.size = Vector2(strsize, font->get_height(font_size));
+		nr.name.position = offset + Vector2(0, (h - theme_cache.node_title_font->get_height(theme_cache.node_title_font_size)) / 2).floor();
+		nr.name.size = Vector2(name_string_size, theme_cache.node_title_font->get_height(theme_cache.node_title_font_size));
 
-		state_machine_draw->draw_string(font, nr.name.position + Vector2(0, font->get_ascent(font_size)), name, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, font_color);
-		offset.x += strsize + sep;
+		state_machine_draw->draw_string(theme_cache.node_title_font, nr.name.position + Vector2(0, theme_cache.node_title_font->get_ascent(theme_cache.node_title_font_size)), name, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.node_title_font_size, theme_cache.node_title_font_color);
+		offset.x += name_string_size + sep;
 
 		nr.can_edit = needs_editor;
 		if (needs_editor) {
-			nr.edit.position = offset + Vector2(0, (h - edit->get_height()) / 2).floor();
-			nr.edit.size = edit->get_size();
+			nr.edit.position = offset + Vector2(0, (h - theme_cache.edit_node->get_height()) / 2).floor();
+			nr.edit.size = theme_cache.edit_node->get_size();
 
-			if (over_node == name && over_node_what == 1) {
-				state_machine_draw->draw_texture(edit, nr.edit.position, accent);
+			if (hovered_node_name == name && hovered_node_area == HOVER_NODE_EDIT) {
+				state_machine_draw->draw_texture(theme_cache.edit_node, nr.edit.position, theme_cache.highlight_color);
 			} else {
-				state_machine_draw->draw_texture(edit, nr.edit.position);
+				state_machine_draw->draw_texture(theme_cache.edit_node, nr.edit.position);
 			}
 		}
 	}
@@ -1229,7 +1213,6 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(String
 	}
 
 	const NodeRect &nr = node_rects[idx];
-
 	if (nr.can_edit) {
 		return; // It is not AnimationNodeAnimation.
 	}
@@ -1246,16 +1229,9 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw_individual(String
 	}
 	to.y = from.y;
 
-	float c = p_ratio;
-	Color fg = get_theme_color(SNAME("font_color"), SNAME("Label"));
-	Color bg = fg;
-	bg.a *= 0.3;
-
-	state_machine_play_pos->draw_line(from, to, bg, 2);
-
-	to = from.lerp(to, c);
-
-	state_machine_play_pos->draw_line(from, to, fg, 2);
+	state_machine_play_pos->draw_line(from, to, theme_cache.playback_background_color, 2);
+	to = from.lerp(to, p_ratio);
+	state_machine_play_pos->draw_line(from, to, theme_cache.playback_color, 2);
 }
 
 void AnimationNodeStateMachineEditor::_state_machine_pos_draw_all() {
@@ -1298,30 +1274,27 @@ void AnimationNodeStateMachineEditor::_update_graph() {
 
 void AnimationNodeStateMachineEditor::_notification(int p_what) {
 	switch (p_what) {
-		case NOTIFICATION_ENTER_TREE:
-		case NOTIFICATION_THEME_CHANGED:
-		case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
-		case NOTIFICATION_TRANSLATION_CHANGED: {
-			error_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
-			error_label->add_theme_color_override("font_color", get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
-			panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree")));
-
-			tool_select->set_icon(get_editor_theme_icon(SNAME("ToolSelect")));
-			tool_create->set_icon(get_editor_theme_icon(SNAME("ToolAddNode")));
-			tool_connect->set_icon(get_editor_theme_icon(SNAME("ToolConnect")));
+		case NOTIFICATION_THEME_CHANGED: {
+			panel->add_theme_style_override("panel", theme_cache.panel_style);
+			error_panel->add_theme_style_override("panel", theme_cache.error_panel_style);
+			error_label->add_theme_color_override("font_color", theme_cache.error_color);
+
+			tool_select->set_icon(theme_cache.tool_icon_select);
+			tool_create->set_icon(theme_cache.tool_icon_create);
+			tool_connect->set_icon(theme_cache.tool_icon_connect);
 
 			switch_mode->clear();
-			switch_mode->add_icon_item(get_editor_theme_icon(SNAME("TransitionImmediate")), TTR("Immediate"));
-			switch_mode->add_icon_item(get_editor_theme_icon(SNAME("TransitionSync")), TTR("Sync"));
-			switch_mode->add_icon_item(get_editor_theme_icon(SNAME("TransitionEnd")), TTR("At End"));
+			switch_mode->add_icon_item(theme_cache.transition_icon_immediate, TTR("Immediate"));
+			switch_mode->add_icon_item(theme_cache.transition_icon_sync, TTR("Sync"));
+			switch_mode->add_icon_item(theme_cache.transition_icon_end, TTR("At End"));
 
-			auto_advance->set_icon(get_editor_theme_icon(SNAME("AutoPlay")));
+			auto_advance->set_icon(theme_cache.play_icon_auto);
 
-			tool_erase->set_icon(get_editor_theme_icon(SNAME("Remove")));
+			tool_erase->set_icon(theme_cache.tool_icon_erase);
 
 			play_mode->clear();
-			play_mode->add_icon_item(get_editor_theme_icon(SNAME("PlayTravel")), TTR("Travel"));
-			play_mode->add_icon_item(get_editor_theme_icon(SNAME("Play")), TTR("Immediate"));
+			play_mode->add_icon_item(theme_cache.play_icon_travel, TTR("Travel"));
+			play_mode->add_icon_item(theme_cache.play_icon_start, TTR("Immediate"));
 		} break;
 
 		case NOTIFICATION_PROCESS: {
@@ -1486,7 +1459,8 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) {
 		} break;
 
 		case NOTIFICATION_VISIBILITY_CHANGED: {
-			over_node = StringName();
+			hovered_node_name = StringName();
+			hovered_node_area = HOVER_NODE_NONE;
 			set_process(is_visible_in_tree());
 		} break;
 	}
@@ -1638,6 +1612,56 @@ void AnimationNodeStateMachineEditor::_bind_methods() {
 	ClassDB::bind_method("_delete_selected", &AnimationNodeStateMachineEditor::_delete_selected);
 	ClassDB::bind_method("_delete_all", &AnimationNodeStateMachineEditor::_delete_all);
 	ClassDB::bind_method("_delete_tree_draw", &AnimationNodeStateMachineEditor::_delete_tree_draw);
+
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, panel_style, "panel", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, error_panel_style, "error_panel", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, error_color, "error_color", "GraphStateMachine");
+
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, tool_icon_select, "ToolSelect", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, tool_icon_create, "ToolAddNode", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, tool_icon_connect, "ToolConnect", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, tool_icon_erase, "Remove", "EditorIcons");
+
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icon_immediate, "TransitionImmediate", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icon_sync, "TransitionSync", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icon_end, "TransitionEnd", "EditorIcons");
+
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, play_icon_start, "Play", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, play_icon_travel, "PlayTravel", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, play_icon_auto, "AutoPlay", "EditorIcons");
+
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, animation_icon, "Animation", "EditorIcons");
+
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, node_frame, "node_frame", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, node_frame_selected, "node_frame_selected", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, node_frame_playing, "node_frame_playing", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, node_frame_start, "node_frame_start", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, AnimationNodeStateMachineEditor, node_frame_end, "node_frame_end", "GraphStateMachine");
+
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_FONT, AnimationNodeStateMachineEditor, node_title_font, "node_title_font", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_FONT_SIZE, AnimationNodeStateMachineEditor, node_title_font_size, "node_title_font_size", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, node_title_font_color, "node_title_font_color", "GraphStateMachine");
+
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, play_node, "Play", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, edit_node, "Edit", "EditorIcons");
+
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, transition_color, "transition_color", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, transition_disabled_color, "transition_disabled_color", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, transition_icon_color, "transition_icon_color", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, transition_icon_disabled_color, "transition_icon_disabled_color", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, highlight_color, "highlight_color", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, highlight_disabled_color, "highlight_disabled_color", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, guideline_color, "guideline_color", "GraphStateMachine");
+
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[0], "TransitionImmediateBig", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[1], "TransitionSyncBig", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[2], "TransitionEndBig", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[3], "TransitionImmediateAutoBig", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[4], "TransitionSyncAutoBig", "EditorIcons");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, AnimationNodeStateMachineEditor, transition_icons[5], "TransitionEndAutoBig", "EditorIcons");
+
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, playback_color, "playback_color", "GraphStateMachine");
+	BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, AnimationNodeStateMachineEditor, playback_background_color, "playback_background_color", "GraphStateMachine");
 }
 
 AnimationNodeStateMachineEditor *AnimationNodeStateMachineEditor::singleton = nullptr;
@@ -1803,15 +1827,6 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() {
 
 	Button *delete_all = delete_window->add_button(TTR("Delete All"), true);
 	delete_all->connect("pressed", callable_mp(this, &AnimationNodeStateMachineEditor::_delete_all));
-
-	over_node_what = -1;
-	dragging_selected_attempt = false;
-	connecting = false;
-	selected_transition_index = -1;
-
-	last_active = false;
-
-	error_time = 0;
 }
 
 void EditorAnimationMultiTransitionEdit::add_transition(const StringName &p_from, const StringName &p_to, Ref<AnimationNodeStateMachineTransition> p_transition) {

+ 60 - 3
editor/plugins/animation_state_machine_editor.h

@@ -78,6 +78,53 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
 	PanelContainer *error_panel = nullptr;
 	Label *error_label = nullptr;
 
+	struct ThemeCache {
+		Ref<StyleBox> panel_style;
+		Ref<StyleBox> error_panel_style;
+		Color error_color;
+
+		Ref<Texture2D> tool_icon_select;
+		Ref<Texture2D> tool_icon_create;
+		Ref<Texture2D> tool_icon_connect;
+		Ref<Texture2D> tool_icon_erase;
+
+		Ref<Texture2D> transition_icon_immediate;
+		Ref<Texture2D> transition_icon_sync;
+		Ref<Texture2D> transition_icon_end;
+
+		Ref<Texture2D> play_icon_start;
+		Ref<Texture2D> play_icon_travel;
+		Ref<Texture2D> play_icon_auto;
+
+		Ref<Texture2D> animation_icon;
+
+		Ref<StyleBox> node_frame;
+		Ref<StyleBox> node_frame_selected;
+		Ref<StyleBox> node_frame_playing;
+		Ref<StyleBox> node_frame_start;
+		Ref<StyleBox> node_frame_end;
+
+		Ref<Font> node_title_font;
+		int node_title_font_size = 0;
+		Color node_title_font_color;
+
+		Ref<Texture2D> play_node;
+		Ref<Texture2D> edit_node;
+
+		Color transition_color;
+		Color transition_disabled_color;
+		Color transition_icon_color;
+		Color transition_icon_disabled_color;
+		Color highlight_color;
+		Color highlight_disabled_color;
+		Color guideline_color;
+
+		Ref<Texture2D> transition_icons[6]{};
+
+		Color playback_color;
+		Color playback_background_color;
+	} theme_cache;
+
 	bool updating = false;
 
 	static AnimationNodeStateMachineEditor *singleton;
@@ -176,11 +223,17 @@ class AnimationNodeStateMachineEditor : public AnimationTreeNodeEditorPlugin {
 
 	StringName selected_transition_from;
 	StringName selected_transition_to;
-	int selected_transition_index;
+	int selected_transition_index = -1;
 	void _add_transition(const bool p_nested_action = false);
 
-	StringName over_node;
-	int over_node_what = -1;
+	enum HoveredNodeArea {
+		HOVER_NODE_NONE = -1,
+		HOVER_NODE_PLAY = 0,
+		HOVER_NODE_EDIT = 1,
+	};
+
+	StringName hovered_node_name;
+	HoveredNodeArea hovered_node_area = HOVER_NODE_NONE;
 
 	String prev_name;
 	void _name_edited(const String &p_text);
@@ -240,9 +293,13 @@ protected:
 
 public:
 	static AnimationNodeStateMachineEditor *get_singleton() { return singleton; }
+
 	virtual bool can_edit(const Ref<AnimationNode> &p_node) override;
 	virtual void edit(const Ref<AnimationNode> &p_node) override;
+
 	virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
+	virtual String get_tooltip(const Point2 &p_pos) const override;
+
 	AnimationNodeStateMachineEditor();
 };
 

+ 2 - 2
scene/animation/animation_blend_space_1d.cpp

@@ -177,12 +177,12 @@ void AnimationNodeBlendSpace1D::set_blend_point_node(int p_point, const Ref<Anim
 }
 
 float AnimationNodeBlendSpace1D::get_blend_point_position(int p_point) const {
-	ERR_FAIL_INDEX_V(p_point, blend_points_used, 0);
+	ERR_FAIL_INDEX_V(p_point, MAX_BLEND_POINTS, 0);
 	return blend_points[p_point].position;
 }
 
 Ref<AnimationRootNode> AnimationNodeBlendSpace1D::get_blend_point_node(int p_point) const {
-	ERR_FAIL_INDEX_V(p_point, blend_points_used, Ref<AnimationRootNode>());
+	ERR_FAIL_INDEX_V(p_point, MAX_BLEND_POINTS, Ref<AnimationRootNode>());
 	return blend_points[p_point].node;
 }
 

+ 2 - 2
scene/animation/animation_blend_space_2d.cpp

@@ -114,12 +114,12 @@ void AnimationNodeBlendSpace2D::set_blend_point_node(int p_point, const Ref<Anim
 }
 
 Vector2 AnimationNodeBlendSpace2D::get_blend_point_position(int p_point) const {
-	ERR_FAIL_INDEX_V(p_point, blend_points_used, Vector2());
+	ERR_FAIL_INDEX_V(p_point, MAX_BLEND_POINTS, Vector2());
 	return blend_points[p_point].position;
 }
 
 Ref<AnimationRootNode> AnimationNodeBlendSpace2D::get_blend_point_node(int p_point) const {
-	ERR_FAIL_INDEX_V(p_point, blend_points_used, Ref<AnimationRootNode>());
+	ERR_FAIL_INDEX_V(p_point, MAX_BLEND_POINTS, Ref<AnimationRootNode>());
 	return blend_points[p_point].node;
 }