使用导航网格

2D 和 3D 版本的导航网格分别为 NavigationPolygonNavigationMesh

备注

导航网格描述的只是代理中心位置的可达区域,会忽略代理可能存在的半径值。如果你想要让寻路考虑代理的(碰撞)尺寸,就需要让导航网格收缩对应的量。

Navigation works independently from other engine parts like rendering or physics. Navigation meshes are the only things considered when doing pathfinding, e.g. visuals and collision shapes for example are completely ignored by the navigation system. If you need to take other data (like visuals for example) into account when doing pathfinding, you need to adapt your navigation meshes accordingly. The process of factoring in navigation restrictions in navigation meshes is commonly referred to as navigation mesh baking.

If you experience clipping or collision problems while following navigation paths, always remember that you need to tell the navigation system what your intentions are through an appropriate navigation mesh. By itself the navigation system will never know “this is a tree / rock / wall collision shape or visual mesh” because it only knows that “here I was told I can path safely because it is on a navigation mesh”.

创建 2D 导航网格

Navigation meshes in the 2D editor are created with the help of the NavigationPolygon draw tools that appear in the top bar of the editor when a NavigationRegion2D is selected.

../../_images/nav_polydrawtool.png

The NavigationPolygon draw tools can be used to create and edit navigation meshes by defining outline polygons. The outline polygons are later converted to real navigation mesh resources for the NavigationServer regions.

../../_images/nav_polymatroschka.png

Multiple outlines can be added to the same NavigationPolygon resource as long as they do not intersect or overlap. Each additional outline will cut a hole in the polygon created by the larger outline. If the larger polygon is already a hole, it will create a new navigation mesh polygon inside.

Outlines are not a replacement if the intention is to merge aligned polygons e.g. from grid cells. Outlines, as the name would suggest, cannot intersect each other or have any overlapping vertex positions.

../../_images/nav_polyoutlinefail.png

Outline layouts like seen in this picture will fail the convex partitioning required by the navigation mesh generation. In these layout cases, the outline tool cannot be used. Use the Geometry2D class to merge or intersect polygons to create a merged mesh that is valid for navigation.

备注

The NavigationServer does not connect navigation mesh islands from the same navigation mesh resource. Do not create multiple disconnected islands in the same NavigationRegion2D or NavigationPolygon resource if they should be later connected.

For 2D, no similar navigation mesh baking with geometry parsing exists like in 3D. The Geometry2D class functions for offset, merge, intersect, and clip can be used to shrink or enlarge existing NavigationPolygons for different actor sizes.

创建 3D 导航网格

../../_images/baked_navmesh.png

3D 编辑器中的导航网格是借助 NavigationMeshGenerator 单例创建的,使用的是编辑器检查器中显示的 NavigationMesh 烘焙设置。

Navigation mesh baking is the process of creating a simplified mesh used for pathfinding out of (complex) 3D level geometry. For this process Godot parses scene geometry and hands the raw mesh or collision data to the third-party ReCast library for processing and creation of the final navigation mesh.

The resulting navigation mesh is an approximation of the source geometry surfaces for both performance and technical reasons. Do not expect the navigation mesh to perfectly follow the original surfaces. Especially navigation polygons placed over ramps will not keep an equal distance to the ground surface. To align an actor perfectly with the ground use other means like physics.

警告

网格必须先三角形化,然后才能用作导航网格。不支持四边形、NGon 等网格面格式。

运行时烘焙 NavigationMesh

To rebake a NavigationMesh at runtime, use the NavigationRegion3D.bake_navigation_mesh() function. Another option is to use the NavigationMeshGenerator.bake() singleton function with the NavigationMesh resource directly. If the NavigationMesh resource is already prepared, the region can be updated with the NavigationServer3D API directly as well.

GDScript

  1. extends NavigationRegion3D
  2. func update_navigation_mesh():
  3. # use bake and update function of region
  4. var on_thread: bool = true
  5. bake_navigation_mesh(on_thread)
  6. # or use the NavigationMeshGenerator singleton
  7. var _navigationmesh: NavigationMesh = navigation_mesh
  8. NavigationMeshGenerator.bake(_navigationmesh, self)
  9. # remove old resource first to trigger a full update
  10. navigation_mesh = null
  11. navigation_mesh = _navigationmesh
  12. # or use NavigationServer API to update region with prepared navigation mesh
  13. var region_rid: RID = get_region_rid()
  14. NavigationServer3D.region_set_navigation_mesh(region_rid, navigation_mesh)

备注

Baking a NavigationMesh at runtime is a costly operation. A complex navigation mesh takes some time to bake and if done on the main thread can freeze a game. (Re)baking a large navigation mesh is preferably done in a separate thread.

警告

NavigationMesh 资源的 cell_size 等属性的取值需要与实际存储的网格数据相匹配,这样才能正确合并不同的导航网格。

NavigationRegion2D and NavigationRegion3D both use meshes to mark traversable areas, only the tools to create them are different.

For 2D, NavigationPolygon resources are used to draw outline points in the editor. From these outline points the NavigationServer2D creates a mesh to upload navigation data to the NavigationServer.

For 3D, NavigationMesh resources are used. Instead of providing draw tools the 3D variant provides an extensive amount of parameters to bake a navigation mesh directly from 3D source geometry.

备注

Technically there is no hard distinction between 2D and 3D on how to use the given toolsets to create flat navigation meshes. The 2D drawing tool can be used to create a flat 3D navigation mesh and the 3D baking tool can be used to parse flat 3D geometry into appropriate 2D navigation meshes.

根据 CollisionPolygon 创建 2D 导航网格

The following script parses all child nodes of a NavigationRegion2D for CollisionPolygons and bakes their shape into the NavigationPolygon. As the NavigationPolygon creates the navigation mesh from outline data the shapes cannot overlap.

GDScript

  1. extends NavigationRegion2D
  2. var new_navigation_polygon: NavigationPolygon = get_navigation_polygon()
  3. func _ready():
  4. parse_2d_collisionshapes(self)
  5. new_navigation_polygon.make_polygons_from_outlines()
  6. set_navigation_polygon(new_navigation_polygon)
  7. func parse_2d_collisionshapes(root_node: Node2D):
  8. for node in root_node.get_children():
  9. if node.get_child_count() > 0:
  10. parse_2d_collisionshapes(node)
  11. if node is CollisionPolygon2D:
  12. var collisionpolygon_transform: Transform2D = node.get_global_transform()
  13. var collisionpolygon: PackedVector2Array = node.polygon
  14. var new_collision_outline: PackedVector2Array = collisionpolygon_transform * collisionpolygon
  15. new_navigation_polygon.add_outline(new_collision_outline)

程序式 2D 导航网格

The following script creates a new 2D navigation region and fills it with procedurally generated navigation mesh data from a NavigationPolygon resource.

GDScript

  1. extends Node2D
  2. var new_2d_region_rid: RID = NavigationServer2D.region_create()
  3. var default_2d_map_rid: RID = get_world_2d().get_navigation_map()
  4. NavigationServer2D.region_set_map(new_2d_region_rid, default_2d_map_rid)
  5. var new_navigation_polygon: NavigationPolygon = NavigationPolygon.new()
  6. var new_outline: PackedVector2Array = PackedVector2Array([
  7. Vector2(0.0, 0.0),
  8. Vector2(50.0, 0.0),
  9. Vector2(50.0, 50.0),
  10. Vector2(0.0, 50.0),
  11. ])
  12. new_navigation_polygon.add_outline(new_outline)
  13. new_navigation_polygon.make_polygons_from_outlines()
  14. NavigationServer2D.region_set_navigation_polygon(new_2d_region_rid, new_navigation_polygon)

程序式 3D 导航网格

The following script creates a new 3D navigation region and fills it with procedurally generated navigation mesh data from a NavigationMesh resource.

GDScript

  1. extends Node3D
  2. var new_3d_region_rid: RID = NavigationServer3D.region_create()
  3. var default_3d_map_rid: RID = get_world_3d().get_navigation_map()
  4. NavigationServer3D.region_set_map(new_3d_region_rid, default_3d_map_rid)
  5. var new_navigation_mesh: NavigationMesh = NavigationMesh.new()
  6. # Add vertices for a triangle.
  7. new_navigation_mesh.vertices = PackedVector3Array([
  8. Vector3(-1.0, 0.0, 1.0),
  9. Vector3(1.0, 0.0, 1.0),
  10. Vector3(1.0, 0.0, -1.0)
  11. ])
  12. # Add indices for the polygon.
  13. new_navigation_mesh.add_polygon(
  14. PackedInt32Array([0, 1, 2])
  15. )
  16. NavigationServer3D.region_set_navigation_mesh(new_3d_region_rid, new_navigation_mesh)

3D GridMap 的导航网格

The following script creates a new 3D navigation mesh for each GridMap items, clears the current grid cells, and adds new procedural grid cells with the new navigation mesh.

GDScript

  1. extends GridMap
  2. # enable navigation mesh for grid items
  3. set_bake_navigation(true)
  4. # get grid items, create and set a new navigation mesh for each item in the MeshLibrary
  5. var gridmap_item_list: PackedInt32Array = mesh_library.get_item_list()
  6. for item in gridmap_item_list:
  7. var new_item_navigation_mesh: NavigationMesh = NavigationMesh.new()
  8. # Add vertices and polygons that describe the traversable ground surface.
  9. # E.g. for a convex polygon that resembles a flat square.
  10. new_item_navigation_mesh.vertices = PackedVector3Array([
  11. Vector3(-1.0, 0.0, 1.0),
  12. Vector3(1.0, 0.0, 1.0),
  13. Vector3(1.0, 0.0, -1.0),
  14. Vector3(-1.0, 0.0, -1.0),
  15. ])
  16. new_item_navigation_mesh.add_polygon(
  17. PackedInt32Array([0, 1, 2, 3])
  18. )
  19. mesh_library.set_item_navigation_mesh(item, new_item_navigation_mesh)
  20. mesh_library.set_item_navigation_mesh_transform(item, Transform3D())
  21. # clear the cells
  22. clear()
  23. # add procedural cells using the first item
  24. var _position: Vector3i = Vector3i(global_transform.origin)
  25. var _item: int = 0
  26. var _orientation: int = 0
  27. for i in range(0,10):
  28. for j in range(0,10):
  29. _position.x = i
  30. _position.z = j
  31. gridmap.set_cell_item(_position, _item, _orientation)
  32. _position.x = -i
  33. _position.z = -j
  34. gridmap.set_cell_item(_position, _item, _orientation)

Previous Next


© 版权所有 2014-present Juan Linietsky, Ariel Manzur and the Godot community (CC BY 3.0). Revision b1c660f7.

Built with Sphinx using a theme provided by Read the Docs.