navigation_using_navigationpaths.rst 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. .. _doc_navigation_using_navigationpaths:
  2. Using NavigationPaths
  3. =====================
  4. Obtaining a NavigationPath
  5. --------------------------
  6. Navigation paths can be directly queried from the NavigationServer and do not require any
  7. additional nodes or objects as long as the navigation map has a navigation mesh to work with.
  8. To obtain a 2D path, use ``NavigationServer2D.map_get_path(map, from, to, optimize, navigation_layers)``.
  9. To obtain a 3D path, use ``NavigationServer3D.map_get_path(map, from, to, optimize, navigation_layers)``.
  10. For more customizable navigation path queries that require additional setup see :ref:`doc_navigation_using_navigationpathqueryobjects`.
  11. One of the required parameters for the query is the RID of the navigation map.
  12. Each game world has a default navigation map automatically created.
  13. The default navigation maps can be retrieved with ``get_world_2d().get_navigation_map()`` from
  14. any Node2D inheriting node or ``get_world_3d().get_navigation_map()`` from any Node3D inheriting node.
  15. The second and third parameters are the starting position and the target position as Vector2 for 2D or Vector3 for 3D.
  16. If the ``optimized`` parameter is ``true``, path positions will be shortened along polygon
  17. corners with an additional funnel algorithm pass. This works well for free movement
  18. on navigation meshes with unequally sized polygons as the path will hug around corners
  19. along the polygon corridor found by the A* algorithm. With small cells the A* algorithm
  20. creates a very narrow funnel corridor that can create ugly corner paths when used with grids.
  21. If the ``optimized`` parameter is ``false``, path positions will be placed at the center of each polygon edge.
  22. This works well for pure grid movement on navigation meshes with equally sized polygons as the path will go through the center of the grid cells.
  23. Outside of grids due to polygons often covering large open areas with a single, long edge this can create paths with unnecessary long detours.
  24. .. tabs::
  25. .. code-tab:: gdscript 2D GDScript
  26. extends Node2D
  27. # Basic query for a navigation path using the default navigation map.
  28. func get_navigation_path(p_start_position: Vector2, p_target_position: Vector2) -> PackedVector2Array:
  29. if not is_inside_tree():
  30. return PackedVector2Array()
  31. var default_map_rid: RID = get_world_2d().get_navigation_map()
  32. var path: PackedVector2Array = NavigationServer2D.map_get_path(
  33. default_map_rid,
  34. p_start_position,
  35. p_target_position,
  36. true
  37. )
  38. return path
  39. .. code-tab:: csharp 2D C#
  40. using Godot;
  41. using System;
  42. public partial class MyNode2D : Node2D
  43. {
  44. // Basic query for a navigation path using the default navigation map.
  45. private Vector2[] GetNavigationPath(Vector2 startPosition, Vector2 targetPosition)
  46. {
  47. if (!IsInsideTree())
  48. {
  49. return Array.Empty<Vector2>();
  50. }
  51. Rid defaultMapRid = GetWorld2D().NavigationMap;
  52. Vector2[] path = NavigationServer2D.MapGetPath(
  53. defaultMapRid,
  54. startPosition,
  55. targetPosition,
  56. true
  57. );
  58. return path;
  59. }
  60. }
  61. .. code-tab:: gdscript 3D GDScript
  62. extends Node3D
  63. # Basic query for a navigation path using the default navigation map.
  64. func get_navigation_path(p_start_position: Vector3, p_target_position: Vector3) -> PackedVector3Array:
  65. if not is_inside_tree():
  66. return PackedVector3Array()
  67. var default_map_rid: RID = get_world_3d().get_navigation_map()
  68. var path: PackedVector3Array = NavigationServer3D.map_get_path(
  69. default_map_rid,
  70. p_start_position,
  71. p_target_position,
  72. true
  73. )
  74. return path
  75. .. code-tab:: csharp 3D C#
  76. using Godot;
  77. using System;
  78. public partial class MyNode3D : Node3D
  79. {
  80. // Basic query for a navigation path using the default navigation map.
  81. private Vector3[] GetNavigationPath(Vector3 startPosition, Vector3 targetPosition)
  82. {
  83. if (!IsInsideTree())
  84. {
  85. return Array.Empty<Vector3>();
  86. }
  87. Rid defaultMapRid = GetWorld3D().NavigationMap;
  88. Vector3[] path = NavigationServer3D.MapGetPath(
  89. defaultMapRid,
  90. startPosition,
  91. targetPosition,
  92. true
  93. );
  94. return path;
  95. }
  96. }
  97. A returned ``path`` by the NavigationServer will be a ``PackedVector2Array`` for 2D or a ``PackedVector3Array`` for 3D.
  98. These are just a memory-optimized ``Array`` of vector positions.
  99. All position vectors inside the array are guaranteed to be inside a NavigationPolygon or NavigationMesh.
  100. The path array, if not empty, has the navigation mesh position closest to the starting position at the first index ``path[0]`` position.
  101. The closest available navigation mesh position to the target position is the last index ``path[path.size()-1]`` position.
  102. All indexes between are the path points that an actor should follow to reach the target without leaving the navigation mesh.
  103. .. note::
  104. If the target position is on a different navigation mesh that is not merged or connected
  105. the navigation path will lead to the closest possible position on the starting position navigation mesh.
  106. The following script moves a Node3D inheriting node along a navigation path using
  107. the default navigation map by setting the target position with ``set_movement_target()``.
  108. .. tabs::
  109. .. code-tab:: gdscript GDScript
  110. @onready var default_3d_map_rid: RID = get_world_3d().get_navigation_map()
  111. var movement_speed: float = 4.0
  112. var movement_delta: float
  113. var path_point_margin: float = 0.5
  114. var current_path_index: int = 0
  115. var current_path_point: Vector3
  116. var current_path: PackedVector3Array
  117. func set_movement_target(target_position: Vector3):
  118. var start_position: Vector3 = global_transform.origin
  119. current_path = NavigationServer3D.map_get_path(
  120. default_3d_map_rid,
  121. start_position,
  122. target_position,
  123. true
  124. )
  125. if not current_path.is_empty():
  126. current_path_index = 0
  127. current_path_point = current_path[0]
  128. func _physics_process(delta):
  129. if current_path.is_empty():
  130. return
  131. movement_delta = movement_speed * delta
  132. if global_transform.origin.distance_to(current_path_point) <= path_point_margin:
  133. current_path_index += 1
  134. if current_path_index >= current_path.size():
  135. current_path = []
  136. current_path_index = 0
  137. current_path_point = global_transform.origin
  138. return
  139. current_path_point = current_path[current_path_index]
  140. var new_velocity: Vector3 = global_transform.origin.direction_to(current_path_point) * movement_delta
  141. global_transform.origin = global_transform.origin.move_toward(global_transform.origin + new_velocity, movement_delta)
  142. .. code-tab:: csharp
  143. using Godot;
  144. public partial class MyNode3D : Node3D
  145. {
  146. private Rid _default3DMapRid;
  147. private float _movementSpeed = 4.0f;
  148. private float _movementDelta;
  149. private float _pathPointMargin = 0.5f;
  150. private int _currentPathIndex = 0;
  151. private Vector3 _currentPathPoint;
  152. private Vector3[] _currentPath;
  153. public override void _Ready()
  154. {
  155. _default3DMapRid = GetWorld3D().NavigationMap;
  156. }
  157. private void SetMovementTarget(Vector3 targetPosition)
  158. {
  159. Vector3 startPosition = GlobalTransform.Origin;
  160. _currentPath = NavigationServer3D.MapGetPath(_default3DMapRid, startPosition, targetPosition, true);
  161. if (!_currentPath.IsEmpty())
  162. {
  163. _currentPathIndex = 0;
  164. _currentPathPoint = _currentPath[0];
  165. }
  166. }
  167. public override void _PhysicsProcess(double delta)
  168. {
  169. if (_currentPath.IsEmpty())
  170. {
  171. return;
  172. }
  173. _movementDelta = _movementSpeed * (float)delta;
  174. if (GlobalTransform.Origin.DistanceTo(_currentPathPoint) <= _pathPointMargin)
  175. {
  176. _currentPathIndex += 1;
  177. if (_currentPathIndex >= _currentPath.Length)
  178. {
  179. _currentPath = Array.Empty<Vector3>();
  180. _currentPathIndex = 0;
  181. _currentPathPoint = GlobalTransform.Origin;
  182. return;
  183. }
  184. }
  185. _currentPathPoint = _currentPath[_currentPathIndex];
  186. Vector3 newVelocity = GlobalTransform.Origin.DirectionTo(_currentPathPoint) * _movementDelta;
  187. var globalTransform = GlobalTransform;
  188. globalTransform.Origin = globalTransform.Origin.MoveToward(globalTransform.Origin + newVelocity, _movementDelta);
  189. GlobalTransform = globalTransform;
  190. }
  191. }