diff --git a/doc/classes/NavigationRegion2D.xml b/doc/classes/NavigationRegion2D.xml index 05cd49f323a..46e60def9fc 100644 --- a/doc/classes/NavigationRegion2D.xml +++ b/doc/classes/NavigationRegion2D.xml @@ -30,6 +30,12 @@ Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32. + + + + Returns the current navigation map [RID] used by this region. + + @@ -52,6 +58,13 @@ Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32. + + + + + Sets the [RID] of the navigation map this region should use. By default the region will automatically join the [World2D] default navigation map so this function is only required to override the default map. + + diff --git a/doc/classes/NavigationRegion3D.xml b/doc/classes/NavigationRegion3D.xml index 88b4f0dbf16..be1c8cf35e2 100644 --- a/doc/classes/NavigationRegion3D.xml +++ b/doc/classes/NavigationRegion3D.xml @@ -30,6 +30,12 @@ Returns whether or not the specified layer of the [member navigation_layers] bitmask is enabled, given a [param layer_number] between 1 and 32. + + + + Returns the current navigation map [RID] used by this region. + + @@ -44,6 +50,13 @@ Based on [param value], enables or disables the specified layer in the [member navigation_layers] bitmask, given a [param layer_number] between 1 and 32. + + + + + Sets the [RID] of the navigation map this region should use. By default the region will automatically join the [World3D] default navigation map so this function is only required to override the default map. + + diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 693e03e1d4e..529545de978 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -48,9 +48,9 @@ void NavigationRegion2D::set_enabled(bool p_enabled) { } if (!enabled) { - NavigationServer2D::get_singleton()->region_set_map(region, RID()); + _region_enter_navigation_map(); } else { - NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); + _region_exit_navigation_map(); } #ifdef DEBUG_ENABLED @@ -161,17 +161,7 @@ bool NavigationRegion2D::_edit_is_selected_on_click(const Point2 &p_point, doubl void NavigationRegion2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - if (enabled) { - NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - if (constrain_avoidance_obstacles[i].is_valid()) { - NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], get_world_2d()->get_navigation_map()); - NavigationServer2D::get_singleton()->obstacle_set_position(constrain_avoidance_obstacles[i], get_global_position()); - } - } - } - current_global_transform = get_global_transform(); - NavigationServer2D::get_singleton()->region_set_transform(region, current_global_transform); + _region_enter_navigation_map(); } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -179,30 +169,11 @@ void NavigationRegion2D::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { - NavigationServer2D::get_singleton()->region_set_map(region, RID()); - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - if (constrain_avoidance_obstacles[i].is_valid()) { - NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], RID()); - } - } + _region_exit_navigation_map(); } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { set_physics_process_internal(false); - if (is_inside_tree()) { - Transform2D new_global_transform = get_global_transform(); - if (current_global_transform != new_global_transform) { - current_global_transform = new_global_transform; - NavigationServer2D::get_singleton()->region_set_transform(region, current_global_transform); - queue_redraw(); - - for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { - if (constrain_avoidance_obstacles[i].is_valid()) { - NavigationServer2D::get_singleton()->obstacle_set_position(constrain_avoidance_obstacles[i], get_global_position()); - } - } - } - } } break; case NOTIFICATION_DRAW: { @@ -240,6 +211,30 @@ Ref NavigationRegion2D::get_navigation_polygon() const { return navigation_polygon; } +void NavigationRegion2D::set_navigation_map(RID p_navigation_map) { + if (map_override == p_navigation_map) { + return; + } + + map_override = p_navigation_map; + + NavigationServer2D::get_singleton()->region_set_map(region, map_override); + for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { + if (constrain_avoidance_obstacles[i].is_valid()) { + NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], map_override); + } + } +} + +RID NavigationRegion2D::get_navigation_map() const { + if (map_override.is_valid()) { + return map_override; + } else if (is_inside_tree()) { + return get_world_2d()->get_navigation_map(); + } + return RID(); +} + void NavigationRegion2D::_navigation_polygon_changed() { if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) { queue_redraw(); @@ -277,6 +272,9 @@ void NavigationRegion2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion2D::set_enabled); ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion2D::is_enabled); + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationRegion2D::set_navigation_map); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationRegion2D::get_navigation_map); + ClassDB::bind_method(D_METHOD("set_use_edge_connections", "enabled"), &NavigationRegion2D::set_use_edge_connections); ClassDB::bind_method(D_METHOD("get_use_edge_connections"), &NavigationRegion2D::get_use_edge_connections); @@ -416,7 +414,11 @@ void NavigationRegion2D::_update_avoidance_constrain() { NavigationServer2D::get_singleton()->obstacle_set_vertices(obstacle_rid, new_obstacle_outline); NavigationServer2D::get_singleton()->obstacle_set_avoidance_layers(obstacle_rid, avoidance_layers); if (is_inside_tree()) { - NavigationServer2D::get_singleton()->obstacle_set_map(obstacle_rid, get_world_2d()->get_navigation_map()); + if (map_override.is_valid()) { + NavigationServer2D::get_singleton()->obstacle_set_map(obstacle_rid, map_override); + } else { + NavigationServer2D::get_singleton()->obstacle_set_map(obstacle_rid, get_world_2d()->get_navigation_map()); + } NavigationServer2D::get_singleton()->obstacle_set_position(obstacle_rid, get_global_position()); } } @@ -472,6 +474,68 @@ bool NavigationRegion2D::get_avoidance_layer_value(int p_layer_number) const { return get_avoidance_layers() & (1 << (p_layer_number - 1)); } +void NavigationRegion2D::_region_enter_navigation_map() { + if (!is_inside_tree()) { + return; + } + + if (enabled) { + if (map_override.is_valid()) { + NavigationServer2D::get_singleton()->region_set_map(region, map_override); + for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { + if (constrain_avoidance_obstacles[i].is_valid()) { + NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], map_override); + } + } + } else { + NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); + for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { + if (constrain_avoidance_obstacles[i].is_valid()) { + NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], get_world_2d()->get_navigation_map()); + } + } + } + } + + current_global_transform = get_global_transform(); + NavigationServer2D::get_singleton()->region_set_transform(region, current_global_transform); + for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { + if (constrain_avoidance_obstacles[i].is_valid()) { + NavigationServer2D::get_singleton()->obstacle_set_position(constrain_avoidance_obstacles[i], get_global_position()); + } + } + + queue_redraw(); +} + +void NavigationRegion2D::_region_exit_navigation_map() { + NavigationServer2D::get_singleton()->region_set_map(region, RID()); + for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { + if (constrain_avoidance_obstacles[i].is_valid()) { + NavigationServer2D::get_singleton()->obstacle_set_map(constrain_avoidance_obstacles[i], RID()); + } + } +} + +void NavigationRegion2D::_region_update_transform() { + if (!is_inside_tree()) { + return; + } + + Transform2D new_global_transform = get_global_transform(); + if (current_global_transform != new_global_transform) { + current_global_transform = new_global_transform; + NavigationServer2D::get_singleton()->region_set_transform(region, current_global_transform); + for (uint32_t i = 0; i < constrain_avoidance_obstacles.size(); i++) { + if (constrain_avoidance_obstacles[i].is_valid()) { + NavigationServer2D::get_singleton()->obstacle_set_position(constrain_avoidance_obstacles[i], get_global_position()); + } + } + } + + queue_redraw(); +} + #ifdef DEBUG_ENABLED void NavigationRegion2D::_update_debug_mesh() { Vector navigation_polygon_vertices = navigation_polygon->get_vertices(); diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index 642f1663cd4..0a48b10f470 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -40,6 +40,7 @@ class NavigationRegion2D : public Node2D { bool use_edge_connections = true; RID region; + RID map_override; uint32_t navigation_layers = 1; real_t enter_cost = 0.0; real_t travel_cost = 1.0; @@ -79,6 +80,9 @@ public: void set_enabled(bool p_enabled); bool is_enabled() const; + void set_navigation_map(RID p_navigation_map); + RID get_navigation_map() const; + void set_use_edge_connections(bool p_enabled); bool get_use_edge_connections() const; @@ -115,6 +119,9 @@ public: private: void _update_avoidance_constrain(); + void _region_enter_navigation_map(); + void _region_exit_navigation_map(); + void _region_update_transform(); }; #endif // NAVIGATION_REGION_2D_H diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 4c2f56b7b3b..194d3082dfd 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -46,9 +46,9 @@ void NavigationRegion3D::set_enabled(bool p_enabled) { } if (!enabled) { - NavigationServer3D::get_singleton()->region_set_map(region, RID()); + _region_enter_navigation_map(); } else { - NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map()); + _region_exit_navigation_map(); } #ifdef DEBUG_ENABLED @@ -169,17 +169,7 @@ RID NavigationRegion3D::get_region_rid() const { void NavigationRegion3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - if (enabled) { - NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map()); - } - current_global_transform = get_global_transform(); - NavigationServer3D::get_singleton()->region_set_transform(region, current_global_transform); - -#ifdef DEBUG_ENABLED - if (NavigationServer3D::get_singleton()->get_debug_navigation_enabled()) { - _update_debug_mesh(); - } -#endif // DEBUG_ENABLED + _region_enter_navigation_map(); } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -188,31 +178,11 @@ void NavigationRegion3D::_notification(int p_what) { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { set_physics_process_internal(false); - if (is_inside_tree()) { - Transform3D new_global_transform = get_global_transform(); - if (current_global_transform != new_global_transform) { - current_global_transform = new_global_transform; - NavigationServer3D::get_singleton()->region_set_transform(region, current_global_transform); -#ifdef DEBUG_ENABLED - if (debug_instance.is_valid()) { - RS::get_singleton()->instance_set_transform(debug_instance, current_global_transform); - } -#endif // DEBUG_ENABLED - } - } + _region_update_transform(); } break; case NOTIFICATION_EXIT_TREE: { - NavigationServer3D::get_singleton()->region_set_map(region, RID()); - -#ifdef DEBUG_ENABLED - if (debug_instance.is_valid()) { - RS::get_singleton()->instance_set_visible(debug_instance, false); - } - if (debug_edge_connections_instance.is_valid()) { - RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false); - } -#endif // DEBUG_ENABLED + _region_exit_navigation_map(); } break; } } @@ -260,6 +230,25 @@ Ref NavigationRegion3D::get_navigation_mesh() const { return navigation_mesh; } +void NavigationRegion3D::set_navigation_map(RID p_navigation_map) { + if (map_override == p_navigation_map) { + return; + } + + map_override = p_navigation_map; + + NavigationServer3D::get_singleton()->region_set_map(region, map_override); +} + +RID NavigationRegion3D::get_navigation_map() const { + if (map_override.is_valid()) { + return map_override; + } else if (is_inside_tree()) { + return get_world_3d()->get_navigation_map(); + } + return RID(); +} + struct BakeThreadsArgs { NavigationRegion3D *nav_region = nullptr; Ref source_geometry_data; @@ -330,6 +319,9 @@ void NavigationRegion3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion3D::set_enabled); ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion3D::is_enabled); + ClassDB::bind_method(D_METHOD("set_navigation_map", "navigation_map"), &NavigationRegion3D::set_navigation_map); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &NavigationRegion3D::get_navigation_map); + ClassDB::bind_method(D_METHOD("set_use_edge_connections", "enabled"), &NavigationRegion3D::set_use_edge_connections); ClassDB::bind_method(D_METHOD("get_use_edge_connections"), &NavigationRegion3D::get_use_edge_connections); @@ -397,6 +389,58 @@ void NavigationRegion3D::_navigation_map_changed(RID p_map) { } #endif // DEBUG_ENABLED +void NavigationRegion3D::_region_enter_navigation_map() { + if (!is_inside_tree()) { + return; + } + + if (enabled) { + if (map_override.is_valid()) { + NavigationServer3D::get_singleton()->region_set_map(region, map_override); + } else { + NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map()); + } + } + + current_global_transform = get_global_transform(); + NavigationServer3D::get_singleton()->region_set_transform(region, current_global_transform); + +#ifdef DEBUG_ENABLED + if (NavigationServer3D::get_singleton()->get_debug_navigation_enabled()) { + _update_debug_mesh(); + } +#endif // DEBUG_ENABLED +} + +void NavigationRegion3D::_region_exit_navigation_map() { + NavigationServer3D::get_singleton()->region_set_map(region, RID()); +#ifdef DEBUG_ENABLED + if (debug_instance.is_valid()) { + RS::get_singleton()->instance_set_visible(debug_instance, false); + } + if (debug_edge_connections_instance.is_valid()) { + RS::get_singleton()->instance_set_visible(debug_edge_connections_instance, false); + } +#endif // DEBUG_ENABLED +} + +void NavigationRegion3D::_region_update_transform() { + if (!is_inside_tree()) { + return; + } + + Transform3D new_global_transform = get_global_transform(); + if (current_global_transform != new_global_transform) { + current_global_transform = new_global_transform; + NavigationServer3D::get_singleton()->region_set_transform(region, current_global_transform); +#ifdef DEBUG_ENABLED + if (debug_instance.is_valid()) { + RS::get_singleton()->instance_set_transform(debug_instance, current_global_transform); + } +#endif // DEBUG_ENABLED + } +} + NavigationRegion3D::NavigationRegion3D() { set_notify_transform(true); diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index 84b57d064f1..e41d07f4cf6 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -41,6 +41,7 @@ class NavigationRegion3D : public Node3D { bool use_edge_connections = true; RID region; + RID map_override; uint32_t navigation_layers = 1; real_t enter_cost = 0.0; real_t travel_cost = 1.0; @@ -77,6 +78,9 @@ public: void set_enabled(bool p_enabled); bool is_enabled() const; + void set_navigation_map(RID p_navigation_map); + RID get_navigation_map() const; + void set_use_edge_connections(bool p_enabled); bool get_use_edge_connections() const; @@ -106,6 +110,11 @@ public: NavigationRegion3D(); ~NavigationRegion3D(); + +private: + void _region_enter_navigation_map(); + void _region_exit_navigation_map(); + void _region_update_transform(); }; #endif // NAVIGATION_REGION_3D_H