Skip to content

Commit e7058b5

Browse files
authored
Merge pull request godotengine#8714 from smix8/navmesh_examples
Improve navigation mesh code examples
2 parents b39e8a1 + df8b911 commit e7058b5

File tree

1 file changed

+105
-45
lines changed

1 file changed

+105
-45
lines changed

tutorials/navigation/navigation_using_navigationmeshes.rst

Lines changed: 105 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)