@@ -229,95 +229,152 @@ There are some common user problems and important caveats to consider when creat
229229 Remove the geometry that is on the ground inside the other geometry. If that is not possible, add smaller "dummy" geometry inside with as few triangles as possible so the cells
230230 are occupied with something.
231231
232+ Navigation mesh script templates
233+ --------------------------------
234+
235+ The following script uses the NavigationServer to parse source geometry from the scene tree, bakes a navigation mesh, and updates a navigation region with the updated navigation mesh.
236+
232237.. tabs ::
233238 .. code-tab :: gdscript 2D GDScript
234239
235240 extends Node2D
236241
237- func parse_and_bake_navigation_mesh_and_create_region() -> void:
238- # Note, the navigation mesh is not baked here, it only holds the parse parameters.
239- var navigation_mesh: NavigationPolygon = NavigationPolygon.new()
240- # Create the source geometry that will hold the parsed data.
241- var source_geometry := NavigationMeshSourceGeometryData2D.new()
242- # The Node where the parsing should start traversing the SceneTree.
242+ var navigation_mesh: NavigationPolygon
243+ var source_geometry : NavigationMeshSourceGeometryData2D
244+ var callback_parsing : Callable
245+ var callback_baking : Callable
246+ var region_rid: RID
247+
248+ func _ready() -> void:
249+ navigation_mesh = NavigationPolygon.new()
250+ navigation_mesh.agent_radius = 10.0
251+ source_geometry = NavigationMeshSourceGeometryData2D.new()
252+ callback_parsing = on_parsing_done
253+ callback_baking = on_baking_done
254+ region_rid = NavigationServer2D.region_create()
255+
256+ # Enable the region and set it to the default navigation map.
257+ NavigationServer2D.region_set_enabled(region_rid, true)
258+ NavigationServer2D.region_set_map(region_rid, get_world_2d().get_navigation_map())
259+
260+ # Some mega-nodes like TileMap are often not ready on the first frame.
261+ # Also the parsing needs to happen on the main-thread.
262+ # So do a deferred call to avoid common parsing issues.
263+ parse_source_geometry.call_deferred()
264+
265+ func parse_source_geometry() -> void:
266+ source_geometry.clear()
243267 var root_node: Node2D = self
244268
269+ # Parse the obstruction outlines from all child nodes of the root node by default.
245270 NavigationServer2D.parse_source_geometry_data(
246271 navigation_mesh,
247272 source_geometry,
248- root_node
273+ root_node,
274+ callback_parsing
249275 )
250276
251- # Bake the navigation mesh with the source geometry data.
277+ func on_parsing_done() -> void:
278+ # If we did not parse a TileMap with navigation mesh cells we may now only
279+ # have obstruction outlines so add at least one traversable outline
280+ # so the obstructions outlines have something to "cut" into.
281+ source_geometry.add_traversable_outline(PackedVector2Array([
282+ Vector2(0.0, 0.0),
283+ Vector2(500.0, 0.0),
284+ Vector2(500.0, 500.0),
285+ Vector2(0.0, 500.0)
286+ ]))
287+
288+ # Bake the navigation mesh on a thread with the source geometry data.
252289 NavigationServer2D.bake_from_source_geometry_data_async(
253290 navigation_mesh,
254- source_geometry
291+ source_geometry,
292+ callback_baking
255293 )
256294
257- # Create a new navigation region and update the region with prepared navigation mesh.
258- var region_rid: RID = NavigationServer2D.region_create()
295+ func on_baking_done() -> void:
296+ # Update the region with the updated navigation mesh.
259297 NavigationServer2D.region_set_navigation_polygon(region_rid, navigation_mesh)
260- NavigationServer2D.region_set_enabled(region_rid, true)
261- NavigationServer2D.region_set_map(region_rid, get_world_2d().get_navigation_map())
262298
263299 .. code-tab :: gdscript 3D GDScript
264300
265301 extends Node3D
266302
267- func parse_and_bake_navigation_mesh_and_create_region() -> void:
268- # Note, the navigation mesh is not baked here, it only holds the parse parameters.
269- var navigation_mesh: NavigationMesh = NavigationMesh.new()
270- # Create the source geometry that will hold the parsed data.
271- var source_geometry := NavigationMeshSourceGeometryData3D.new()
272- # The Node where the parsing should start traversing the SceneTree.
303+ var navigation_mesh: NavigationMesh
304+ var source_geometry : NavigationMeshSourceGeometryData3D
305+ var callback_parsing : Callable
306+ var callback_baking : Callable
307+ var region_rid: RID
308+
309+ func _ready() -> void:
310+ navigation_mesh = NavigationMesh.new()
311+ navigation_mesh.agent_radius = 0.5
312+ source_geometry = NavigationMeshSourceGeometryData3D.new()
313+ callback_parsing = on_parsing_done
314+ callback_baking = on_baking_done
315+ region_rid = NavigationServer3D.region_create()
316+
317+ # Enable the region and set it to the default navigation map.
318+ NavigationServer3D.region_set_enabled(region_rid, true)
319+ NavigationServer3D.region_set_map(region_rid, get_world_3d().get_navigation_map())
320+
321+ # Some mega-nodes like GridMap are often not ready on the first frame.
322+ # Also the parsing needs to happen on the main-thread.
323+ # So do a deferred call to avoid common parsing issues.
324+ parse_source_geometry.call_deferred()
325+
326+ func parse_source_geometry() -> void:
327+ source_geometry.clear()
273328 var root_node: Node3D = self
274329
330+ # Parse the geometry from all mesh child nodes of the root node by default.
275331 NavigationServer3D.parse_source_geometry_data(
276332 navigation_mesh,
277333 source_geometry,
278- root_node
334+ root_node,
335+ callback_parsing
279336 )
280337
281- # Bake the navigation mesh with the source geometry data.
338+ func on_parsing_done() -> void:
339+ # Bake the navigation mesh on a thread with the source geometry data.
282340 NavigationServer3D.bake_from_source_geometry_data_async(
283341 navigation_mesh,
284- source_geometry
342+ source_geometry,
343+ callback_baking
285344 )
286345
287- # Create a new navigation region and update the region with prepared navigation mesh.
288- var region_rid: RID = NavigationServer3D.region_create()
346+ func on_baking_done() -> void:
347+ # Update the region with the updated navigation mesh.
289348 NavigationServer3D.region_set_navigation_mesh(region_rid, navigation_mesh)
290- NavigationServer3D.region_set_enabled(region_rid, true)
291- NavigationServer3D.region_set_map(region_rid, get_world_3d().get_navigation_map())
292-
293- Navigation mesh script templates
294- --------------------------------
295349
296- The following script creates a new navigation region and fills it with procedurally generated navigation mesh data.
350+ The following script uses the NavigationServer to update a navigation region with procedurally generated navigation mesh data.
297351
298352.. tabs ::
299353 .. code-tab :: gdscript 2D GDScript
300354
301355 extends Node2D
302356
303- func _ready() -> void:
304- var new_2d_region_rid : RID = NavigationServer2D.region_create()
357+ var navigation_mesh: NavigationPolygon
358+ var region_rid : RID
305359
306- var default_2d_map_rid: RID = get_world_2d().get_navigation_map()
307- NavigationServer2D.region_set_map(new_2d_region_rid, default_2d_map_rid)
360+ func _ready() -> void:
361+ navigation_mesh = NavigationPolygon.new()
362+ region_rid = NavigationServer2D.region_create()
308363
309- var new_navigation_mesh: NavigationPolygon = NavigationPolygon.new()
364+ # Enable the region and set it to the default navigation map.
365+ NavigationServer2D.region_set_enabled(region_rid, true)
366+ NavigationServer2D.region_set_map(region_rid, get_world_2d().get_navigation_map())
310367
311368 # Add vertices for a convex polygon.
312- new_navigation_mesh .vertices = PackedVector2Array([
369+ navigation_mesh .vertices = PackedVector2Array([
313370 Vector2(0.0, 0.0),
314371 Vector2(100.0, 0.0),
315372 Vector2(100.0, 100.0),
316373 Vector2(0.0, 100.0)
317374 ])
318375
319376 # Add indices for the polygon.
320- new_navigation_mesh .add_polygon(
377+ navigation_mesh .add_polygon(
321378 PackedInt32Array([0, 1, 2, 3])
322379 )
323380
@@ -327,25 +384,28 @@ The following script creates a new navigation region and fills it with procedura
327384
328385 extends Node3D
329386
330- func _ready() -> void:
331- var new_3d_region_rid : RID = NavigationServer3D.region_create()
387+ var navigation_mesh: NavigationMesh
388+ var region_rid : RID
332389
333- var default_3d_map_rid: RID = get_world_3d().get_navigation_map()
334- NavigationServer3D.region_set_map(new_3d_region_rid, default_3d_map_rid)
390+ func _ready() -> void:
391+ navigation_mesh = NavigationMesh.new()
392+ region_rid = NavigationServer3D.region_create()
335393
336- var new_navigation_mesh: NavigationMesh = NavigationMesh.new()
394+ # Enable the region and set it to the default navigation map.
395+ NavigationServer3D.region_set_enabled(region_rid, true)
396+ NavigationServer3D.region_set_map(region_rid, get_world_3d().get_navigation_map())
337397
338398 # Add vertices for a convex polygon.
339- new_navigation_mesh .vertices = PackedVector3Array([
399+ navigation_mesh .vertices = PackedVector3Array([
340400 Vector3(-1.0, 0.0, 1.0),
341401 Vector3(1.0, 0.0, 1.0),
342402 Vector3(1.0, 0.0, -1.0),
343403 Vector3(-1.0, 0.0, -1.0),
344404 ])
345405
346406 # Add indices for the polygon.
347- new_navigation_mesh .add_polygon(
407+ navigation_mesh .add_polygon(
348408 PackedInt32Array([0, 1, 2, 3])
349409 )
350410
351- NavigationServer3D.region_set_navigation_mesh(new_3d_region_rid, new_navigation_mesh )
411+ NavigationServer3D.region_set_navigation_mesh(new_3d_region_rid, navigation_mesh )
0 commit comments