Browse Source

Merge pull request #77191 from smix8/navigationregion_map_change_4.x

Add NavigationRegion function to change navigation map
Yuri Sizov 2 years ago
parent
commit
4e66c4cdd9

+ 13 - 0
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.
 			</description>
 		</method>
+		<method name="get_navigation_map" qualifiers="const">
+			<return type="RID" />
+			<description>
+				Returns the current navigation map [RID] used by this region.
+			</description>
+		</method>
 		<method name="get_region_rid" qualifiers="const">
 			<return type="RID" />
 			<description>
@@ -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.
 			</description>
 		</method>
+		<method name="set_navigation_map">
+			<return type="void" />
+			<param index="0" name="navigation_map" type="RID" />
+			<description>
+				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.
+			</description>
+		</method>
 	</methods>
 	<members>
 		<member name="avoidance_layers" type="int" setter="set_avoidance_layers" getter="get_avoidance_layers" default="1">

+ 13 - 0
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.
 			</description>
 		</method>
+		<method name="get_navigation_map" qualifiers="const">
+			<return type="RID" />
+			<description>
+				Returns the current navigation map [RID] used by this region.
+			</description>
+		</method>
 		<method name="get_region_rid" qualifiers="const">
 			<return type="RID" />
 			<description>
@@ -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.
 			</description>
 		</method>
+		<method name="set_navigation_map">
+			<return type="void" />
+			<param index="0" name="navigation_map" type="RID" />
+			<description>
+				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.
+			</description>
+		</method>
 	</methods>
 	<members>
 		<member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true">

+ 98 - 34
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<NavigationPolygon> 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<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices();

+ 7 - 0
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

+ 79 - 35
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<NavigationMesh> 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<NavigationMeshSourceGeometryData3D> 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);
 

+ 9 - 0
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