navigation_using_navigationagents.rst 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762
  1. .. _doc_navigation_using_navigationagents:
  2. Using NavigationAgents
  3. ======================
  4. NavigationsAgents are helper nodes that combine functionality
  5. for pathfinding, path following and agent avoidance for a Node2D/3D inheriting parent node.
  6. They facilitate common calls to the NavigationServer API on
  7. behalf of the parent actor node in a more convenient manner for beginners.
  8. 2D and 3D version of NavigationAgents are available as
  9. :ref:`NavigationAgent2D<class_NavigationAgent2D>` and
  10. :ref:`NavigationAgent3D<class_NavigationAgent3D>` respectively.
  11. New NavigationAgent nodes will automatically join the default navigation map on the :ref:`World2D<class_World2D>`/:ref:`World3D<class_World3D>`.
  12. NavigationsAgent nodes are optional and not a hard requirement to use the navigation system.
  13. Their entire functionality can be replaced with scripts and direct calls to the NavigationServer API.
  14. .. tip::
  15. For more advanced uses consider :ref:`doc_navigation_using_navigationpathqueryobjects` over NavigationAgent nodes.
  16. NavigationAgent Pathfinding
  17. ---------------------------
  18. NavigationAgents query a new navigation path on their current navigation map when their ``target_position`` is set with a global position.
  19. The result of the pathfinding can be influenced with the following properties.
  20. - The ``navigation_layers`` bitmask can be used to limit the navigation meshes that the agent can use.
  21. - The ``pathfinding_algorithm`` controls how the pathfinding travels through the navigation mesh polygons in the path search.
  22. - The ``path_postprocessing`` sets if or how the raw path corridor found by the pathfinding is altered before it is returned.
  23. - The ``path_metadata_flags`` enable the collection of additional path point meta data returned by the path.
  24. - The ``simplify_path`` and ``simplify_epsilon`` properties can be used to remove less critical points from the path.
  25. .. warning::
  26. Disabling path meta flags will disable related signal emissions on the agent.
  27. NavigationAgent Pathfollowing
  28. -----------------------------
  29. After a ``target_position`` has been set for the agent, the next position to follow in the path
  30. can be retrieved with the ``get_next_path_position()`` function.
  31. Once the next path position is received, move the parent actor node of the agent
  32. towards this path position with your own movement code.
  33. .. note::
  34. The navigation system never moves the parent node of a NavigationAgent.
  35. The movement is entirely in the hands of users and their custom scripts.
  36. NavigationAgents have their own internal logic to proceed with the current path and call for updates.
  37. The ``get_next_path_position()`` function is responsible for updating many of the agent's internal states and properties.
  38. The function should be repeatedly called *once* every ``physics_process`` until ``is_navigation_finished()`` tells that the path is finished.
  39. The function should not be called after the target position or path end has been reached
  40. as it can make the agent jitter in place due to the repeated path updates.
  41. Always check very early in script with ``is_navigation_finished()`` if the path is already finished.
  42. The following distance properties influence the path following behavior.
  43. - At ``path_desired_distance`` from the next path position, the agent advances its internal path index to the subsequent next path position.
  44. - At ``target_desired_distance`` from the target path position, the agent considers the target position to be reached and the path at its end.
  45. - At ``path_max_distance`` from the ideal path to the next path position, the agent requests a new path because it was pushed too far off.
  46. The important updates are all triggered with the ``get_next_path_position()`` function
  47. when called in ``_physics_process()``.
  48. NavigationAgents can be used with ``process`` but are still limited to a single update that happens in ``physics_process``.
  49. Script examples for various nodes commonly used with NavigationAgents can be found further below.
  50. Pathfollowing common problems
  51. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  52. There are some common user problems and important caveats to consider when writing agent movement scripts.
  53. - The path is returned empty
  54. If an agent queries a path before the navigation map synchronisation, e.g. in a ``_ready()`` function, the path might return empty. In this case the ``get_next_path_position()`` function will return the same position as the agent parent node and the agent will consider the path end reached. This is fixed by making a deferred call or using a callback e.g. waiting for the navigation map changed signal.
  55. - The agent is stuck dancing between two positions
  56. This is usually caused by very frequent path updates every single frame, either deliberate or by accident (e.g. max path distance set too short). The pathfinding needs to find the closest position that are valid on navigation mesh. If a new path is requested every single frame the first path positions might end up switching constantly in front and behind the agent's current position, causing it to dance between the two positions.
  57. - The agent is backtracking sometimes
  58. If an agent moves very fast it might overshoot the path_desired_distance check without ever advancing the path index. This can lead to the agent backtracking to the path point now behind it until it passes the distance check to increase the path index. Increase the desired distances accordingly for your agent speed and update rate usually fixes this as well as a more balanced navigation mesh polygon layout with not too many polygon edges cramped together in small spaces.
  59. - The agent is sometimes looking backwards for a frame
  60. Same as with stuck dancing agents between two positions, this is usually caused by very frequent path updates every single frame. Depending on your navigation mesh layout, and especially when an agent is directly placed over a navigation mesh edge or edge connection, expect path positions to be sometimes slightly "behind" your actors current orientation. This happens due to precision issues and can not always be avoided. This is usually only a visible problem if actors are instantly rotated to face the current path position.
  61. NavigationAgent Avoidance
  62. -------------------------
  63. This section explains how to use the navigation avoidance specific to NavigationAgents.
  64. In order for NavigationAgents to use the avoidance feature the ``avoidance_enabled`` property must be set to ``true``.
  65. .. image:: img/agent_avoidance_enabled.png
  66. The ``velocity_computed`` signal of the NavigationAgent node must be connected to receive the safe velocity calculation result.
  67. .. image:: img/agent_safevelocity_signal.png
  68. Set the ``velocity`` of the NavigationAgent node in ``_physics_process()`` to update the agent with the current velocity of the agent's parent node.
  69. While avoidance is enabled on the agent the ``safe_velocity`` vector will be received with the velocity_computed signal every physics frame.
  70. This velocity vector should be used to move the NavigationAgent's parent node in order to avoidance collision with other avoidance using agents or avoidance obstacles.
  71. .. note::
  72. Only other agents on the same map that are registered for avoidance themself will be considered in the avoidance calculation.
  73. The following NavigationAgent properties are relevant for avoidance:
  74. - The property ``height`` is available in 3D only. The height together with the current global y-axis position of the agent determines the vertical placement of the agent in the avoidance simulation. Agents using the 2D avoidance will automatically ignore other agents or obstacles that are below or above them.
  75. - The property ``radius`` controls the size of the avoidance circle, or in case of 3D sphere, around the agent. This area describes the agents body and not the avoidance maneuver distance.
  76. - The property ``neighbor_distance`` controls the search radius of the agent when searching for other agents that should be avoided. A lower value reduces processing cost.
  77. - The property ``max_neighbors`` controls how many other agents are considered in the avoidance calculation if they all have overlapping radius.
  78. A lower value reduces processing cost but a too low value may result in agents ignoring the avoidance.
  79. - The properties ``time_horizon_agents`` and ``time_horizon_obstacles`` control the avoidance prediction time for other agents or obstacles in seconds. When agents calculate their safe velocities they choose velocities that can be kept for this amount of seconds without colliding with another avoidance object. The prediction time should be kept as low as possible as agents will slow down their velocities to avoid collision in that timeframe.
  80. - The property ``max_speed`` controls the maximum velocity allowed for the agents avoidance calculation.
  81. If the agents parents moves faster than this value the avoidance ``safe_velocity`` might not be accurate enough to avoid collision.
  82. - The property ``use_3d_avoidance`` switches the agent between the 2D avoidance (xz axis) and the 3D avoidance (xyz axis) on the next update.
  83. Note that 2D avoidance and 3D avoidance run in separate avoidance simulations so agents split between them do not affect each other.
  84. - The properties ``avoidance_layers`` and ``avoidance_mask`` are bitmasks similar to e.g. physics layers. Agents will only avoid other avoidance objects that are on an avoidance layer that matches at least one of their own avoidance mask bits.
  85. - The ``avoidance_priority`` makes agents with a higher priority ignore agents with a lower priority. This can be used to give certain agents more importance in the avoidance simulation, e.g. important non-playable characters, without constantly changing their entire avoidance layers or mask.
  86. Avoidance exists in its own space and has no information from navigation meshes or physics collision.
  87. Behind the scene avoidance agents are just circles with different radius on a flat 2D plane or spheres in an otherwise empty 3D space.
  88. NavigationObstacles can be used to add some environment constrains to the avoidance simulation, see :ref:`doc_navigation_using_navigationobstacles`.
  89. .. note::
  90. Avoidance does not affect the pathfinding. It should be seen as an additional option for constantly moving objects that cannot be (re)baked to a navigation mesh efficiently in order to move around them.
  91. .. note::
  92. RVO avoidance makes implicit assumptions about natural agent behavior. E.g. that agents move on reasonable passing sides that can be assigned when they encounter each other.
  93. This means that very clinical avoidance test scenarios will commonly fail. E.g. agents moved directly against each other with perfect opposite velocities will fail because the agents can not get their passing sides assigned.
  94. Using the NavigationAgent ``avoidance_enabled`` property is the preferred option
  95. to toggle avoidance. The following code snippets can be used to
  96. toggle avoidance on agents, create or delete avoidance callbacks or switch avoidance modes.
  97. .. tabs::
  98. .. code-tab:: gdscript 2D GDScript
  99. extends NavigationAgent2D
  100. func _ready() -> void:
  101. var agent: RID = get_rid()
  102. # Enable avoidance
  103. NavigationServer2D.agent_set_avoidance_enabled(agent, true)
  104. # Create avoidance callback
  105. NavigationServer2D.agent_set_avoidance_callback(agent, Callable(self, "_avoidance_done"))
  106. # Disable avoidance
  107. NavigationServer2D.agent_set_avoidance_enabled(agent, false)
  108. # Delete avoidance callback
  109. NavigationServer2D.agent_set_avoidance_callback(agent, Callable())
  110. .. code-tab:: csharp 2D C#
  111. using Godot;
  112. public partial class MyNavigationAgent2D : NavigationAgent2D
  113. {
  114. public override void _Ready()
  115. {
  116. Rid agent = GetRid();
  117. // Enable avoidance
  118. NavigationServer2D.AgentSetAvoidanceEnabled(agent, true);
  119. // Create avoidance callback
  120. NavigationServer2D.AgentSetAvoidanceCallback(agent, Callable.From(AvoidanceDone));
  121. // Disable avoidance
  122. NavigationServer2D.AgentSetAvoidanceEnabled(agent, false);
  123. //Delete avoidance callback
  124. NavigationServer2D.AgentSetAvoidanceCallback(agent, default);
  125. }
  126. private void AvoidanceDone() { }
  127. }
  128. .. code-tab:: gdscript 3D GDScript
  129. extends NavigationAgent3D
  130. func _ready() -> void:
  131. var agent: RID = get_rid()
  132. # Enable avoidance
  133. NavigationServer3D.agent_set_avoidance_enabled(agent, true)
  134. # Create avoidance callback
  135. NavigationServer3D.agent_set_avoidance_callback(agent, Callable(self, "_avoidance_done"))
  136. # Switch to 3D avoidance
  137. NavigationServer3D.agent_set_use_3d_avoidance(agent, true)
  138. # Disable avoidance
  139. NavigationServer3D.agent_set_avoidance_enabled(agent, false)
  140. # Delete avoidance callback
  141. NavigationServer3D.agent_set_avoidance_callback(agent, Callable())
  142. # Switch to 2D avoidance
  143. NavigationServer3D.agent_set_use_3d_avoidance(agent, false)
  144. .. code-tab:: csharp 3D C#
  145. using Godot;
  146. public partial class MyNavigationAgent3D : NavigationAgent3D
  147. {
  148. public override void _Ready()
  149. {
  150. Rid agent = GetRid();
  151. // Enable avoidance
  152. NavigationServer3D.AgentSetAvoidanceEnabled(agent, true);
  153. // Create avoidance callback
  154. NavigationServer3D.AgentSetAvoidanceCallback(agent, Callable.From(AvoidanceDone));
  155. // Switch to 3D avoidance
  156. NavigationServer3D.AgentSetUse3DAvoidance(agent, true);
  157. // Disable avoidance
  158. NavigationServer3D.AgentSetAvoidanceEnabled(agent, false);
  159. //Delete avoidance callback
  160. NavigationServer3D.AgentSetAvoidanceCallback(agent, default);
  161. // Switch to 2D avoidance
  162. NavigationServer3D.AgentSetUse3DAvoidance(agent, false);
  163. }
  164. private void AvoidanceDone() { }
  165. }
  166. NavigationAgent Script Templates
  167. --------------------------------
  168. The following sections provides script templates for nodes commonly used with NavigationAgents.
  169. .. tabs::
  170. .. tab:: 2D GDScript
  171. .. tabs::
  172. .. code-tab:: gdscript Node2D
  173. extends Node2D
  174. @export var movement_speed: float = 4.0
  175. @onready var navigation_agent: NavigationAgent2D = get_node("NavigationAgent2D")
  176. var movement_delta: float
  177. func _ready() -> void:
  178. navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))
  179. func set_movement_target(movement_target: Vector2):
  180. navigation_agent.set_target_position(movement_target)
  181. func _physics_process(delta):
  182. # Do not query when the map has never synchronized and is empty.
  183. if NavigationServer2D.map_get_iteration_id(navigation_agent.get_navigation_map()) == 0:
  184. return
  185. if navigation_agent.is_navigation_finished():
  186. return
  187. movement_delta = movement_speed * delta
  188. var next_path_position: Vector2 = navigation_agent.get_next_path_position()
  189. var new_velocity: Vector2 = global_position.direction_to(next_path_position) * movement_delta
  190. if navigation_agent.avoidance_enabled:
  191. navigation_agent.set_velocity(new_velocity)
  192. else:
  193. _on_velocity_computed(new_velocity)
  194. func _on_velocity_computed(safe_velocity: Vector2) -> void:
  195. global_position = global_position.move_toward(global_position + safe_velocity, movement_delta)
  196. .. code-tab:: gdscript CharacterBody2D
  197. extends CharacterBody2D
  198. @export var movement_speed: float = 4.0
  199. @onready var navigation_agent: NavigationAgent2D = get_node("NavigationAgent2D")
  200. func _ready() -> void:
  201. navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))
  202. func set_movement_target(movement_target: Vector2):
  203. navigation_agent.set_target_position(movement_target)
  204. func _physics_process(delta):
  205. # Do not query when the map has never synchronized and is empty.
  206. if NavigationServer2D.map_get_iteration_id(navigation_agent.get_navigation_map()) == 0:
  207. return
  208. if navigation_agent.is_navigation_finished():
  209. return
  210. var next_path_position: Vector2 = navigation_agent.get_next_path_position()
  211. var new_velocity: Vector2 = global_position.direction_to(next_path_position) * movement_speed
  212. if navigation_agent.avoidance_enabled:
  213. navigation_agent.set_velocity(new_velocity)
  214. else:
  215. _on_velocity_computed(new_velocity)
  216. func _on_velocity_computed(safe_velocity: Vector2):
  217. velocity = safe_velocity
  218. move_and_slide()
  219. .. code-tab:: gdscript RigidBody2D
  220. extends RigidBody2D
  221. @export var movement_speed: float = 4.0
  222. @onready var navigation_agent: NavigationAgent2D = get_node("NavigationAgent2D")
  223. func _ready() -> void:
  224. navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))
  225. func set_movement_target(movement_target: Vector2):
  226. navigation_agent.set_target_position(movement_target)
  227. func _physics_process(delta):
  228. # Do not query when the map has never synchronized and is empty.
  229. if NavigationServer2D.map_get_iteration_id(navigation_agent.get_navigation_map()) == 0:
  230. return
  231. if navigation_agent.is_navigation_finished():
  232. return
  233. var next_path_position: Vector2 = navigation_agent.get_next_path_position()
  234. var new_velocity: Vector2 = global_position.direction_to(next_path_position) * movement_speed
  235. if navigation_agent.avoidance_enabled:
  236. navigation_agent.set_velocity(new_velocity)
  237. else:
  238. _on_velocity_computed(new_velocity)
  239. func _on_velocity_computed(safe_velocity: Vector2):
  240. linear_velocity = safe_velocity
  241. .. tab:: 2D C#
  242. .. tabs::
  243. .. code-tab:: csharp Node2D
  244. using Godot;
  245. public partial class MyNode2D : Node2D
  246. {
  247. [Export]
  248. public float MovementSpeed { get; set; } = 4.0f;
  249. NavigationAgent2D _navigationAgent;
  250. private float _movementDelta;
  251. public override void _Ready()
  252. {
  253. _navigationAgent = GetNode<NavigationAgent2D>("NavigationAgent2D");
  254. _navigationAgent.VelocityComputed += OnVelocityComputed;
  255. }
  256. private void SetMovementTarget(Vector2 movementTarget)
  257. {
  258. _navigationAgent.TargetPosition = movementTarget;
  259. }
  260. public override void _PhysicsProcess(double delta)
  261. {
  262. // Do not query when the map has never synchronized and is empty.
  263. if (NavigationServer2D.MapGetIterationId(_navigationAgent.GetNavigationMap()) == 0)
  264. {
  265. return;
  266. }
  267. if (_navigationAgent.IsNavigationFinished())
  268. {
  269. return;
  270. }
  271. _movementDelta = MovementSpeed * (float)delta;
  272. Vector2 nextPathPosition = _navigationAgent.GetNextPathPosition();
  273. Vector2 newVelocity = GlobalPosition.DirectionTo(nextPathPosition) * _movementDelta;
  274. if (_navigationAgent.AvoidanceEnabled)
  275. {
  276. _navigationAgent.Velocity = newVelocity;
  277. }
  278. else
  279. {
  280. OnVelocityComputed(newVelocity);
  281. }
  282. }
  283. private void OnVelocityComputed(Vector2 safeVelocity)
  284. {
  285. GlobalPosition = GlobalPosition.MoveToward(GlobalPosition + safeVelocity, _movementDelta);
  286. }
  287. }
  288. .. code-tab:: csharp CharacterBody2D
  289. using Godot;
  290. public partial class MyCharacterBody2D : CharacterBody2D
  291. {
  292. [Export]
  293. public float MovementSpeed { get; set; } = 4.0f;
  294. NavigationAgent2D _navigationAgent;
  295. public override void _Ready()
  296. {
  297. _navigationAgent = GetNode<NavigationAgent2D>("NavigationAgent2D");
  298. _navigationAgent.VelocityComputed += OnVelocityComputed;
  299. }
  300. private void SetMovementTarget(Vector2 movementTarget)
  301. {
  302. _navigationAgent.TargetPosition = movementTarget;
  303. }
  304. public override void _PhysicsProcess(double delta)
  305. {
  306. // Do not query when the map has never synchronized and is empty.
  307. if (NavigationServer2D.MapGetIterationId(_navigationAgent.GetNavigationMap()) == 0)
  308. {
  309. return;
  310. }
  311. if (_navigationAgent.IsNavigationFinished())
  312. {
  313. return;
  314. }
  315. Vector2 nextPathPosition = _navigationAgent.GetNextPathPosition();
  316. Vector2 newVelocity = GlobalPosition.DirectionTo(nextPathPosition) * MovementSpeed;
  317. if (_navigationAgent.AvoidanceEnabled)
  318. {
  319. _navigationAgent.Velocity = newVelocity;
  320. }
  321. else
  322. {
  323. OnVelocityComputed(newVelocity);
  324. }
  325. }
  326. private void OnVelocityComputed(Vector2 safeVelocity)
  327. {
  328. Velocity = safeVelocity;
  329. MoveAndSlide();
  330. }
  331. }
  332. .. code-tab:: csharp RigidBody2D
  333. using Godot;
  334. public partial class MyRigidBody2D : RigidBody2D
  335. {
  336. [Export]
  337. public float MovementSpeed { get; set; } = 4.0f;
  338. NavigationAgent2D _navigationAgent;
  339. public override void _Ready()
  340. {
  341. _navigationAgent = GetNode<NavigationAgent2D>("NavigationAgent2D");
  342. _navigationAgent.VelocityComputed += OnVelocityComputed;
  343. }
  344. private void SetMovementTarget(Vector2 movementTarget)
  345. {
  346. _navigationAgent.TargetPosition = movementTarget;
  347. }
  348. public override void _PhysicsProcess(double delta)
  349. {
  350. // Do not query when the map has never synchronized and is empty.
  351. if (NavigationServer2D.MapGetIterationId(_navigationAgent.GetNavigationMap()) == 0)
  352. {
  353. return;
  354. }
  355. if (_navigationAgent.IsNavigationFinished())
  356. {
  357. return;
  358. }
  359. Vector2 nextPathPosition = _navigationAgent.GetNextPathPosition();
  360. Vector2 newVelocity = GlobalPosition.DirectionTo(nextPathPosition) * MovementSpeed;
  361. if (_navigationAgent.AvoidanceEnabled)
  362. {
  363. _navigationAgent.Velocity = newVelocity;
  364. }
  365. else
  366. {
  367. OnVelocityComputed(newVelocity);
  368. }
  369. }
  370. private void OnVelocityComputed(Vector2 safeVelocity)
  371. {
  372. LinearVelocity = safeVelocity;
  373. }
  374. }
  375. .. tab:: 3D GDScript
  376. .. tabs::
  377. .. code-tab:: gdscript Node3D
  378. extends Node3D
  379. @export var movement_speed: float = 4.0
  380. @onready var navigation_agent: NavigationAgent3D = get_node("NavigationAgent3D")
  381. var physics_delta: float
  382. func _ready() -> void:
  383. navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))
  384. func set_movement_target(movement_target: Vector3):
  385. navigation_agent.set_target_position(movement_target)
  386. func _physics_process(delta):
  387. # Save the delta for use in _on_velocity_computed.
  388. physics_delta = delta
  389. # Do not query when the map has never synchronized and is empty.
  390. if NavigationServer3D.map_get_iteration_id(navigation_agent.get_navigation_map()) == 0:
  391. return
  392. if navigation_agent.is_navigation_finished():
  393. return
  394. var next_path_position: Vector3 = navigation_agent.get_next_path_position()
  395. var new_velocity: Vector3 = global_position.direction_to(next_path_position) * movement_speed
  396. if navigation_agent.avoidance_enabled:
  397. navigation_agent.set_velocity(new_velocity)
  398. else:
  399. _on_velocity_computed(new_velocity)
  400. func _on_velocity_computed(safe_velocity: Vector3) -> void:
  401. global_position = global_position.move_toward(global_position + safe_velocity, physics_delta * movement_speed)
  402. .. code-tab:: gdscript CharacterBody3D
  403. extends CharacterBody3D
  404. @export var movement_speed: float = 4.0
  405. @onready var navigation_agent: NavigationAgent3D = get_node("NavigationAgent3D")
  406. func _ready() -> void:
  407. navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))
  408. func set_movement_target(movement_target: Vector3):
  409. navigation_agent.set_target_position(movement_target)
  410. func _physics_process(delta):
  411. # Do not query when the map has never synchronized and is empty.
  412. if NavigationServer3D.map_get_iteration_id(navigation_agent.get_navigation_map()) == 0:
  413. return
  414. if navigation_agent.is_navigation_finished():
  415. return
  416. var next_path_position: Vector3 = navigation_agent.get_next_path_position()
  417. var new_velocity: Vector3 = global_position.direction_to(next_path_position) * movement_speed
  418. if navigation_agent.avoidance_enabled:
  419. navigation_agent.set_velocity(new_velocity)
  420. else:
  421. _on_velocity_computed(new_velocity)
  422. func _on_velocity_computed(safe_velocity: Vector3):
  423. velocity = safe_velocity
  424. move_and_slide()
  425. .. code-tab:: gdscript RigidBody3D
  426. extends RigidBody3D
  427. @export var movement_speed: float = 4.0
  428. @onready var navigation_agent: NavigationAgent3D = get_node("NavigationAgent3D")
  429. func _ready() -> void:
  430. navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))
  431. func set_movement_target(movement_target: Vector3):
  432. navigation_agent.set_target_position(movement_target)
  433. func _physics_process(delta):
  434. # Do not query when the map has never synchronized and is empty.
  435. if NavigationServer3D.map_get_iteration_id(navigation_agent.get_navigation_map()) == 0:
  436. return
  437. if navigation_agent.is_navigation_finished():
  438. return
  439. var next_path_position: Vector3 = navigation_agent.get_next_path_position()
  440. var new_velocity: Vector3 = global_position.direction_to(next_path_position) * movement_speed
  441. if navigation_agent.avoidance_enabled:
  442. navigation_agent.set_velocity(new_velocity)
  443. else:
  444. _on_velocity_computed(new_velocity)
  445. func _on_velocity_computed(safe_velocity: Vector3):
  446. linear_velocity = safe_velocity
  447. .. tab:: 3D C#
  448. .. tabs::
  449. .. code-tab:: csharp Node3D
  450. using Godot;
  451. public partial class MyNode3D : Node3D
  452. {
  453. [Export]
  454. public float MovementSpeed { get; set; } = 4.0f;
  455. NavigationAgent3D _navigationAgent;
  456. private float _movementDelta;
  457. public override void _Ready()
  458. {
  459. _navigationAgent = GetNode<NavigationAgent3D>("NavigationAgent3D");
  460. _navigationAgent.VelocityComputed += OnVelocityComputed;
  461. }
  462. private void SetMovementTarget(Vector3 movementTarget)
  463. {
  464. _navigationAgent.TargetPosition = movementTarget;
  465. }
  466. public override void _PhysicsProcess(double delta)
  467. {
  468. // Do not query when the map has never synchronized and is empty.
  469. if (NavigationServer3D.MapGetIterationId(_navigationAgent.GetNavigationMap()) == 0)
  470. {
  471. return;
  472. }
  473. if (_navigationAgent.IsNavigationFinished())
  474. {
  475. return;
  476. }
  477. _movementDelta = MovementSpeed * (float)delta;
  478. Vector3 nextPathPosition = _navigationAgent.GetNextPathPosition();
  479. Vector3 newVelocity = GlobalPosition.DirectionTo(nextPathPosition) * _movementDelta;
  480. if (_navigationAgent.AvoidanceEnabled)
  481. {
  482. _navigationAgent.Velocity = newVelocity;
  483. }
  484. else
  485. {
  486. OnVelocityComputed(newVelocity);
  487. }
  488. }
  489. private void OnVelocityComputed(Vector3 safeVelocity)
  490. {
  491. GlobalPosition = GlobalPosition.MoveToward(GlobalPosition + safeVelocity, _movementDelta);
  492. }
  493. }
  494. .. code-tab:: csharp CharacterBody3D
  495. using Godot;
  496. public partial class MyCharacterBody3D : CharacterBody3D
  497. {
  498. [Export]
  499. public float MovementSpeed { get; set; } = 4.0f;
  500. NavigationAgent3D _navigationAgent;
  501. public override void _Ready()
  502. {
  503. _navigationAgent = GetNode<NavigationAgent3D>("NavigationAgent3D");
  504. _navigationAgent.VelocityComputed += OnVelocityComputed;
  505. }
  506. private void SetMovementTarget(Vector3 movementTarget)
  507. {
  508. _navigationAgent.TargetPosition = movementTarget;
  509. }
  510. public override void _PhysicsProcess(double delta)
  511. {
  512. // Do not query when the map has never synchronized and is empty.
  513. if (NavigationServer3D.MapGetIterationId(_navigationAgent.GetNavigationMap()) == 0)
  514. {
  515. return;
  516. }
  517. if (_navigationAgent.IsNavigationFinished())
  518. {
  519. return;
  520. }
  521. Vector3 nextPathPosition = _navigationAgent.GetNextPathPosition();
  522. Vector3 newVelocity = GlobalPosition.DirectionTo(nextPathPosition) * MovementSpeed;
  523. if (_navigationAgent.AvoidanceEnabled)
  524. {
  525. _navigationAgent.Velocity = newVelocity;
  526. }
  527. else
  528. {
  529. OnVelocityComputed(newVelocity);
  530. }
  531. }
  532. private void OnVelocityComputed(Vector3 safeVelocity)
  533. {
  534. Velocity = safeVelocity;
  535. MoveAndSlide();
  536. }
  537. }
  538. .. code-tab:: csharp RigidBody3D
  539. using Godot;
  540. public partial class MyRigidBody3D : RigidBody3D
  541. {
  542. [Export]
  543. public float MovementSpeed { get; set; } = 4.0f;
  544. NavigationAgent3D _navigationAgent;
  545. public override void _Ready()
  546. {
  547. _navigationAgent = GetNode<NavigationAgent3D>("NavigationAgent3D");
  548. _navigationAgent.VelocityComputed += OnVelocityComputed;
  549. }
  550. private void SetMovementTarget(Vector3 movementTarget)
  551. {
  552. _navigationAgent.TargetPosition = movementTarget;
  553. }
  554. public override void _PhysicsProcess(double delta)
  555. {
  556. // Do not query when the map has never synchronized and is empty.
  557. if (NavigationServer3D.MapGetIterationId(_navigationAgent.GetNavigationMap()) == 0)
  558. {
  559. return;
  560. }
  561. if (_navigationAgent.IsNavigationFinished())
  562. {
  563. return;
  564. }
  565. Vector3 nextPathPosition = _navigationAgent.GetNextPathPosition();
  566. Vector3 newVelocity = GlobalPosition.DirectionTo(nextPathPosition) * MovementSpeed;
  567. if (_navigationAgent.AvoidanceEnabled)
  568. {
  569. _navigationAgent.Velocity = newVelocity;
  570. }
  571. else
  572. {
  573. OnVelocityComputed(newVelocity);
  574. }
  575. }
  576. private void OnVelocityComputed(Vector3 safeVelocity)
  577. {
  578. LinearVelocity = safeVelocity;
  579. }
  580. }