navigation_using_navigationobstacles.rst 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. .. _doc_navigation_using_navigationobstacles:
  2. Using NavigationObstacles
  3. =========================
  4. 2D and 3D versions of NavigationObstacles nodes are available as
  5. :ref:`NavigationObstacle2D<class_NavigationObstacle2D>` and
  6. :ref:`NavigationObstacle3D<class_NavigationObstacle3D>` respectively.
  7. Navigation obstacles are dual purpose in that they can affect both the navigation mesh baking, and the agent avoidance.
  8. - With ``affect_navigation_mesh`` enabled the obstacle will affect navigation mesh when baked.
  9. - With ``avoidance_enabled`` the obstacle will affect avoidance agents.
  10. .. tip::
  11. Avoidance is enabled by default. If the obstacle is not used for avoidance disable ``enabled_avoidance`` to save performance.
  12. Obstacles and navigation mesh
  13. -----------------------------
  14. .. figure:: img/nav_mesh_obstacles.webp
  15. :align: center
  16. :alt: Navigation obstacles affecting navigation mesh baking
  17. Navigation obstacles affecting navigation mesh baking.
  18. For navigation mesh baking, obstacles can be used to discard parts of all other source geometry inside the obstacle shape.
  19. This can be used to stop navigation meshes being baked in unwanted places,
  20. e.g. inside "solid" geometry like thick walls or on top of other geometry that should not be included for gameplay like roofs.
  21. .. figure:: img/nav_mesh_obstacles_discard.webp
  22. :align: center
  23. :alt: Navigation obstacles discard of unwanted navigation mesh
  24. Navigation obstacles discard of unwanted navigation mesh.
  25. An obstacle does not add geometry in the baking process, it only removes geometry.
  26. It does so by nullifying all the (voxel) cells with rasterized source geometry that are within the obstacle shape.
  27. As such its effect and shape detail is limited to the cell resolution used by the baking process.
  28. For more details on the navigation mesh baking see :ref:`doc_navigation_using_navigationmeshes`.
  29. .. image:: img/nav_mesh_obstacles_properties.webp
  30. The property ``affect_navigation_mesh`` makes the obstacle contribute to the navigation mesh baking.
  31. It will be parsed or unparsed like all other node objects in a navigation mesh baking process.
  32. The ``carve_navigation_mesh`` property makes the shape unaffected by offsets of the baking,
  33. e.g. the offset added by the navigation mesh ``agent_radius``.
  34. It will basically act as a stencil and cut into the already offset navigation mesh surface.
  35. It will still be affected by further postprocessing of the baking process like edge simplification.
  36. The obstacle shape and placement is defined with the ``height`` and ``vertices`` properties, and the ``global_position`` of the obstacle.
  37. The y-axis value of any Vector3 used for the vertices is ignored as the obstacle is projected on a flat horizontal plane.
  38. When baking navigation meshes in scripts obstacles can be added procedurally as a projected obstruction.
  39. Obstacles are not involved in the source geometry parsing so adding them just before baking is enough.
  40. .. tabs::
  41. .. code-tab:: gdscript 2D GDScript
  42. var obstacle_outline = PackedVector2Array([
  43. Vector2(-50, -50),
  44. Vector2(50, -50),
  45. Vector2(50, 50),
  46. Vector2(-50, 50)
  47. ])
  48. var navigation_mesh = NavigationPolygon.new()
  49. var source_geometry = NavigationMeshSourceGeometryData2D.new()
  50. NavigationServer2D.parse_source_geometry_data(navigation_mesh, source_geometry, $MyTestRootNode)
  51. var obstacle_carve: bool = true
  52. source_geometry.add_projected_obstruction(obstacle_outline, obstacle_carve)
  53. NavigationServer2D.bake_from_source_geometry_data(navigation_mesh, source_geometry)
  54. .. code-tab:: csharp 2D C#
  55. Vector2[] obstacleOutline = new Vector2[]
  56. {
  57. new Vector2(-50, -50),
  58. new Vector2(50, -50),
  59. new Vector2(50, 50),
  60. new Vector2(-50, 50),
  61. };
  62. var navigationMesh = new NavigationPolygon();
  63. var sourceGeometry = new NavigationMeshSourceGeometryData2D();
  64. NavigationServer2D.ParseSourceGeometryData(navigationMesh, sourceGeometry, GetNode<Node2D>("MyTestRootNode"));
  65. bool obstacleCarve = true;
  66. sourceGeometry.AddProjectedObstruction(obstacleOutline, obstacleCarve);
  67. NavigationServer2D.BakeFromSourceGeometryData(navigationMesh, sourceGeometry);
  68. .. code-tab:: gdscript 3D GDScript
  69. var obstacle_outline = PackedVector3Array([
  70. Vector3(-5, 0, -5),
  71. Vector3(5, 0, -5),
  72. Vector3(5, 0, 5),
  73. Vector3(-5, 0, 5)
  74. ])
  75. var navigation_mesh = NavigationMesh.new()
  76. var source_geometry = NavigationMeshSourceGeometryData3D.new()
  77. NavigationServer3D.parse_source_geometry_data(navigation_mesh, source_geometry, $MyTestRootNode)
  78. var obstacle_elevation: float = $MyTestObstacleNode.global_position.y
  79. var obstacle_height: float = 50.0
  80. var obstacle_carve: bool = true
  81. source_geometry.add_projected_obstruction(obstacle_outline, obstacle_elevation, obstacle_height, obstacle_carve)
  82. NavigationServer3D.bake_from_source_geometry_data(navigation_mesh, source_geometry)
  83. .. code-tab:: csharp 3D C#
  84. Vector3[] obstacleOutline = new Vector3[]
  85. {
  86. new Vector3(-5, 0, -5),
  87. new Vector3(5, 0, -5),
  88. new Vector3(5, 0, 5),
  89. new Vector3(-5, 0, 5),
  90. };
  91. var navigationMesh = new NavigationMesh();
  92. var sourceGeometry = new NavigationMeshSourceGeometryData3D();
  93. NavigationServer3D.ParseSourceGeometryData(navigationMesh, sourceGeometry, GetNode<Node3D>("MyTestRootNode"));
  94. float obstacleElevation = GetNode<Node3D>("MyTestObstacleNode").GlobalPosition.Y;
  95. float obstacleHeight = 50.0f;
  96. bool obstacleCarve = true;
  97. sourceGeometry.AddProjectedObstruction(obstacleOutline, obstacleElevation, obstacleHeight, obstacleCarve);
  98. NavigationServer3D.BakeFromSourceGeometryData(navigationMesh, sourceGeometry);
  99. Obstacles and agent avoidance
  100. -----------------------------
  101. For avoidance navigation obstacles can be used either as static or dynamic obstacles to affect avoidance controlled agents.
  102. - When used statically NavigationObstacles constrain avoidance controlled agents outside or inside a polygon defined area.
  103. - When used dynamically NavigationObstacles push away avoidance controlled agents in a radius around them.
  104. Static avoidance obstacles
  105. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  106. An avoidance obstacle is considered static when its ``vertices`` property is populated with an outline array of positions to form a polygon.
  107. .. figure:: img/nav_static_obstacle_build.gif
  108. :align: center
  109. :alt: Static obstacle drawn in the editor to block or contain navigation agents
  110. Static obstacle drawn in the editor to block or contain navigation agents.
  111. - Static obstacles act as hard do-not-cross boundaries for avoidance using agents, e.g. similar to physics collision but for avoidance.
  112. - Static obstacles define their boundaries with an array of outline ``vertices`` (positions), and in case of 3D with an additional ``height`` property.
  113. - Static obstacles only work for agents that use the 2D avoidance mode.
  114. - Static obstacles define through winding order of the vertices if agents are pushed out or sucked in.
  115. - Static obstacles can not change their position. They can only be warped to a new position and rebuilt from scratch.
  116. Static obstacles as a result are ill-suited for usages where the position is changed every frame, as the constant rebuild has a high performance cost.
  117. - Static obstacles that are warped to another position can not be predicted by agents. This creates the risk of getting agents stuck should a static obstacle be warped on top of agents.
  118. When the 2D avoidance is used in 3D the y-axis of Vector3 vertices is ignored. Instead, the global y-axis position of the obstacle is used as the elevation level. Agents will ignore static obstacles in 3D that are below or above them. This is automatically determined by global y-axis position of both obstacle and agent as the elevation level as well as their respective height properties.
  119. Dynamic avoidance obstacles
  120. ~~~~~~~~~~~~~~~~~~~~~~~~~~~
  121. An avoidance obstacle is considered dynamic when its ``radius`` property is greater than zero.
  122. - Dynamic obstacles act as a soft please-move-away-from-me object for avoidance using agents, e.g. similar to how they avoid other agents.
  123. - Dynamic obstacles define their boundaries with a single ``radius`` for a 2D circle, or in case of 3D avoidance a sphere shape.
  124. - Dynamic obstacles can change their position every frame without additional performance cost.
  125. - Dynamic obstacles with a set velocity can be predicted in their movement by agents.
  126. - Dynamic obstacles are not a reliable way to constrain agents in crowded or narrow spaces.
  127. While both static and dynamic properties can be active at the same time on the same obstacle this is not recommended for performance.
  128. Ideally when an obstacle is moving the static vertices are removed and instead the radius activated.
  129. When the obstacle reaches the new final position it should gradually enlarge its radius to push all other agents away.
  130. With enough created safe space around the obstacle it should add the static vertices again and remove the radius.
  131. This helps avoid getting agents stuck in the suddenly appearing static obstacle when the rebuilt static boundary is finished.
  132. Similar to agents the obstacles can make use of the ``avoidance_layers`` bitmask.
  133. All agents with a matching bit on their own avoidance mask will avoid the obstacle.
  134. Procedural obstacles
  135. --------------------
  136. New obstacles can be created in a script without a Node by using the NavigationServer directly.
  137. Obstacles created with scripts require at least a ``map`` and a ``position``.
  138. For dynamic use a ``radius`` is required.
  139. For static use an array of ``vertices`` is required.
  140. .. tabs::
  141. .. code-tab:: gdscript 2D GDScript
  142. # create a new "obstacle" and place it on the default navigation map.
  143. var new_obstacle_rid: RID = NavigationServer2D.obstacle_create()
  144. var default_map_rid: RID = get_world_2d().get_navigation_map()
  145. NavigationServer2D.obstacle_set_map(new_obstacle_rid, default_map_rid)
  146. NavigationServer2D.obstacle_set_position(new_obstacle_rid, global_position)
  147. # Use obstacle dynamic by increasing radius above zero.
  148. NavigationServer2D.obstacle_set_radius(new_obstacle_rid, 5.0)
  149. # Use obstacle static by adding a square that pushes agents out.
  150. var outline = PackedVector2Array([Vector2(-100, -100), Vector2(100, -100), Vector2(100, 100), Vector2(-100, 100)])
  151. NavigationServer2D.obstacle_set_vertices(new_obstacle_rid, outline)
  152. # Enable the obstacle.
  153. NavigationServer2D.obstacle_set_avoidance_enabled(new_obstacle_rid, true)
  154. .. code-tab:: csharp 2D C#
  155. // Create a new "obstacle" and place it on the default navigation map.
  156. Rid newObstacleRid = NavigationServer2D.ObstacleCreate();
  157. Rid defaultMapRid = GetWorld2D().NavigationMap;
  158. NavigationServer2D.ObstacleSetMap(newObstacleRid, defaultMapRid);
  159. NavigationServer2D.ObstacleSetPosition(newObstacleRid, GlobalPosition);
  160. // Use obstacle dynamic by increasing radius above zero.
  161. NavigationServer2D.ObstacleSetRadius(newObstacleRid, 5.0f);
  162. // Use obstacle static by adding a square that pushes agents out.
  163. Vector2[] outline = new Vector2[]
  164. {
  165. new Vector2(-100, -100),
  166. new Vector2(100, -100),
  167. new Vector2(100, 100),
  168. new Vector2(-100, 100),
  169. };
  170. NavigationServer2D.ObstacleSetVertices(newObstacleRid, outline);
  171. // Enable the obstacle.
  172. NavigationServer2D.ObstacleSetAvoidanceEnabled(newObstacleRid, true);
  173. .. code-tab:: gdscript 3D GDScript
  174. # Create a new "obstacle" and place it on the default navigation map.
  175. var new_obstacle_rid: RID = NavigationServer3D.obstacle_create()
  176. var default_map_rid: RID = get_world_3d().get_navigation_map()
  177. NavigationServer3D.obstacle_set_map(new_obstacle_rid, default_map_rid)
  178. NavigationServer3D.obstacle_set_position(new_obstacle_rid, global_position)
  179. # Use obstacle dynamic by increasing radius above zero.
  180. NavigationServer3D.obstacle_set_radius(new_obstacle_rid, 0.5)
  181. # Use obstacle static by adding a square that pushes agents out.
  182. var outline = PackedVector3Array([Vector3(-5, 0, -5), Vector3(5, 0, -5), Vector3(5, 0, 5), Vector3(-5, 0, 5)])
  183. NavigationServer3D.obstacle_set_vertices(new_obstacle_rid, outline)
  184. # Set the obstacle height on the y-axis.
  185. NavigationServer3D.obstacle_set_height(new_obstacle_rid, 1.0)
  186. # Enable the obstacle.
  187. NavigationServer3D.obstacle_set_avoidance_enabled(new_obstacle_rid, true)
  188. .. code-tab:: csharp 3D C#
  189. // Create a new "obstacle" and place it on the default navigation map.
  190. Rid newObstacleRid = NavigationServer3D.ObstacleCreate();
  191. Rid defaultMapRid = GetWorld3D().NavigationMap;
  192. NavigationServer3D.ObstacleSetMap(newObstacleRid, defaultMapRid);
  193. NavigationServer3D.ObstacleSetPosition(newObstacleRid, GlobalPosition);
  194. // Use obstacle dynamic by increasing radius above zero.
  195. NavigationServer3D.ObstacleSetRadius(newObstacleRid, 5.0f);
  196. // Use obstacle static by adding a square that pushes agents out.
  197. Vector3[] outline = new Vector3[]
  198. {
  199. new Vector3(-5, 0, -5),
  200. new Vector3(5, 0, -5),
  201. new Vector3(5, 0, 5),
  202. new Vector3(-5, 0, 5),
  203. };
  204. NavigationServer3D.ObstacleSetVertices(newObstacleRid, outline);
  205. // Set the obstacle height on the y-axis.
  206. NavigationServer3D.ObstacleSetHeight(newObstacleRid, 1.0f);
  207. // Enable the obstacle.
  208. NavigationServer3D.ObstacleSetAvoidanceEnabled(newObstacleRid, true);