Merge pull request #87504 from smix8/nav_mesh_auto_rebake

Auto-bake edited NavigationPolygons in the Editor on a timer
This commit is contained in:
Rémi Verschelde 2024-02-27 21:22:56 +01:00
commit f80cdeb597
No known key found for this signature in database
GPG key ID: C3336907360768E1
4 changed files with 69 additions and 1 deletions

View file

@ -429,6 +429,9 @@
<member name="editors/panning/warped_mouse_panning" type="bool" setter="" getter=""> <member name="editors/panning/warped_mouse_panning" type="bool" setter="" getter="">
If [code]true[/code], warps the mouse around the 2D viewport while panning in the 2D editor. This makes it possible to pan over a large area without having to exit panning and adjust the mouse cursor. If [code]true[/code], warps the mouse around the 2D viewport while panning in the 2D editor. This makes it possible to pan over a large area without having to exit panning and adjust the mouse cursor.
</member> </member>
<member name="editors/polygon_editor/auto_bake_delay" type="float" setter="" getter="">
The delay in seconds until more complex and performance costly polygon editors commit their outlines, e.g. the 2D navigation polygon editor rebakes the navigation mesh polygons. A negative value stops the auto bake.
</member>
<member name="editors/polygon_editor/point_grab_radius" type="int" setter="" getter=""> <member name="editors/polygon_editor/point_grab_radius" type="int" setter="" getter="">
The radius in which points can be selected in the [Polygon2D] and [CollisionPolygon2D] editors (in pixels). Higher values make it easier to select points quickly, but can make it more difficult to select the expected point when several points are located close to each other. The radius in which points can be selected in the [Polygon2D] and [CollisionPolygon2D] editors (in pixels). Higher values make it easier to select points quickly, but can make it more difficult to select the expected point when several points are located close to each other.
</member> </member>

View file

@ -756,6 +756,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Polygon editor // Polygon editor
_initial_set("editors/polygon_editor/point_grab_radius", has_touchscreen_ui ? 32 : 8); _initial_set("editors/polygon_editor/point_grab_radius", has_touchscreen_ui ? 32 : 8);
_initial_set("editors/polygon_editor/show_previous_outline", true); _initial_set("editors/polygon_editor/show_previous_outline", true);
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/polygon_editor/auto_bake_delay", 1.5, "-1.0,10.0,0.01");
// Animation // Animation
_initial_set("editors/animation/autorename_animation_tracks", true); _initial_set("editors/animation/autorename_animation_tracks", true);

View file

@ -31,6 +31,7 @@
#include "navigation_polygon_editor_plugin.h" #include "navigation_polygon_editor_plugin.h"
#include "editor/editor_node.h" #include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h" #include "editor/editor_undo_redo_manager.h"
#include "scene/2d/navigation_region_2d.h" #include "scene/2d/navigation_region_2d.h"
#include "scene/gui/dialogs.h" #include "scene/gui/dialogs.h"
@ -50,6 +51,13 @@ Node2D *NavigationPolygonEditor::_get_node() const {
void NavigationPolygonEditor::_set_node(Node *p_polygon) { void NavigationPolygonEditor::_set_node(Node *p_polygon) {
node = Object::cast_to<NavigationRegion2D>(p_polygon); node = Object::cast_to<NavigationRegion2D>(p_polygon);
if (node) {
Ref<NavigationPolygon> navpoly = node->get_navigation_polygon();
if (navpoly.is_valid() && navpoly->get_outline_count() > 0 && navpoly->get_polygon_count() == 0) {
// We have outlines drawn / added by the user but no polygons were created for this navmesh yet so let's bake once immediately.
_rebake_timer_timeout();
}
}
} }
int NavigationPolygonEditor::_get_polygon_count() const { int NavigationPolygonEditor::_get_polygon_count() const {
@ -73,6 +81,10 @@ Variant NavigationPolygonEditor::_get_polygon(int p_idx) const {
void NavigationPolygonEditor::_set_polygon(int p_idx, const Variant &p_polygon) const { void NavigationPolygonEditor::_set_polygon(int p_idx, const Variant &p_polygon) const {
Ref<NavigationPolygon> navpoly = _ensure_navpoly(); Ref<NavigationPolygon> navpoly = _ensure_navpoly();
navpoly->set_outline(p_idx, p_polygon); navpoly->set_outline(p_idx, p_polygon);
if (rebake_timer && _rebake_timer_delay >= 0.0) {
rebake_timer->start();
}
} }
void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) { void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) {
@ -80,6 +92,10 @@ void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "add_outline", p_polygon); undo_redo->add_do_method(navpoly.ptr(), "add_outline", p_polygon);
undo_redo->add_undo_method(navpoly.ptr(), "remove_outline", navpoly->get_outline_count()); undo_redo->add_undo_method(navpoly.ptr(), "remove_outline", navpoly->get_outline_count());
if (rebake_timer && _rebake_timer_delay >= 0.0) {
rebake_timer->start();
}
} }
void NavigationPolygonEditor::_action_remove_polygon(int p_idx) { void NavigationPolygonEditor::_action_remove_polygon(int p_idx) {
@ -87,6 +103,10 @@ void NavigationPolygonEditor::_action_remove_polygon(int p_idx) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "remove_outline", p_idx); undo_redo->add_do_method(navpoly.ptr(), "remove_outline", p_idx);
undo_redo->add_undo_method(navpoly.ptr(), "add_outline_at_index", navpoly->get_outline(p_idx), p_idx); undo_redo->add_undo_method(navpoly.ptr(), "add_outline_at_index", navpoly->get_outline(p_idx), p_idx);
if (rebake_timer && _rebake_timer_delay >= 0.0) {
rebake_timer->start();
}
} }
void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) { void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
@ -94,6 +114,10 @@ void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_pr
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "set_outline", p_idx, p_polygon); undo_redo->add_do_method(navpoly.ptr(), "set_outline", p_idx, p_polygon);
undo_redo->add_undo_method(navpoly.ptr(), "set_outline", p_idx, p_previous); undo_redo->add_undo_method(navpoly.ptr(), "set_outline", p_idx, p_previous);
if (rebake_timer && _rebake_timer_delay >= 0.0) {
rebake_timer->start();
}
} }
bool NavigationPolygonEditor::_has_resource() const { bool NavigationPolygonEditor::_has_resource() const {
@ -136,6 +160,15 @@ NavigationPolygonEditor::NavigationPolygonEditor() {
bake_info = memnew(Label); bake_info = memnew(Label);
bake_hbox->add_child(bake_info); bake_hbox->add_child(bake_info);
rebake_timer = memnew(Timer);
add_child(rebake_timer);
rebake_timer->set_one_shot(true);
_rebake_timer_delay = EDITOR_GET("editors/polygon_editor/auto_bake_delay");
if (_rebake_timer_delay >= 0.0) {
rebake_timer->set_wait_time(_rebake_timer_delay);
}
rebake_timer->connect("timeout", callable_mp(this, &NavigationPolygonEditor::_rebake_timer_timeout));
err_dialog = memnew(AcceptDialog); err_dialog = memnew(AcceptDialog);
add_child(err_dialog); add_child(err_dialog);
node = nullptr; node = nullptr;
@ -147,15 +180,26 @@ void NavigationPolygonEditor::_notification(int p_what) {
button_bake->set_icon(get_theme_icon(SNAME("Bake"), SNAME("EditorIcons"))); button_bake->set_icon(get_theme_icon(SNAME("Bake"), SNAME("EditorIcons")));
button_reset->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons"))); button_reset->set_icon(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
} break; } break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
if (rebake_timer) {
_rebake_timer_delay = EDITOR_GET("editors/polygon_editor/auto_bake_delay");
if (_rebake_timer_delay >= 0.0) {
rebake_timer->set_wait_time(_rebake_timer_delay);
}
}
} break;
} }
} }
void NavigationPolygonEditor::_bake_pressed() { void NavigationPolygonEditor::_bake_pressed() {
if (rebake_timer) {
rebake_timer->stop();
}
button_bake->set_pressed(false); button_bake->set_pressed(false);
ERR_FAIL_NULL(node); ERR_FAIL_NULL(node);
Ref<NavigationPolygon> navigation_polygon = node->get_navigation_polygon(); Ref<NavigationPolygon> navigation_polygon = node->get_navigation_polygon();
if (!navigation_polygon.is_valid()) { if (navigation_polygon.is_null()) {
err_dialog->set_text(TTR("A NavigationPolygon resource must be set or created for this node to work.")); err_dialog->set_text(TTR("A NavigationPolygon resource must be set or created for this node to work."));
err_dialog->popup_centered(); err_dialog->popup_centered();
return; return;
@ -167,6 +211,9 @@ void NavigationPolygonEditor::_bake_pressed() {
} }
void NavigationPolygonEditor::_clear_pressed() { void NavigationPolygonEditor::_clear_pressed() {
if (rebake_timer) {
rebake_timer->stop();
}
if (node) { if (node) {
if (node->get_navigation_polygon().is_valid()) { if (node->get_navigation_polygon().is_valid()) {
node->get_navigation_polygon()->clear(); node->get_navigation_polygon()->clear();
@ -193,6 +240,19 @@ void NavigationPolygonEditor::_update_polygon_editing_state() {
} }
} }
void NavigationPolygonEditor::_rebake_timer_timeout() {
if (!node) {
return;
}
Ref<NavigationPolygon> navigation_polygon = node->get_navigation_polygon();
if (!navigation_polygon.is_valid()) {
return;
}
node->bake_navigation_polygon(true);
node->queue_redraw();
}
NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin() : NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin() :
AbstractPolygon2DEditorPlugin(memnew(NavigationPolygonEditor), "NavigationRegion2D") { AbstractPolygon2DEditorPlugin(memnew(NavigationPolygonEditor), "NavigationRegion2D") {
} }

View file

@ -56,6 +56,10 @@ class NavigationPolygonEditor : public AbstractPolygon2DEditor {
Button *button_reset = nullptr; Button *button_reset = nullptr;
Label *bake_info = nullptr; Label *bake_info = nullptr;
Timer *rebake_timer = nullptr;
float _rebake_timer_delay = 1.5;
void _rebake_timer_timeout();
void _bake_pressed(); void _bake_pressed();
void _clear_pressed(); void _clear_pressed();