Work in progress
Godot documentation is being updated to reflect the latest changes in version
4.0. Some documentation pages may
still state outdated information. This banner will tell you if you're reading one of such pages.
The contents of this page are up to date. If you can still find outdated information, please open an issue.
Using Agent Avoidance¶
This section is about how to use agent avoidance with the NavigationServer and documents how agent avoidance is implemented in Godot.
For avoidance with NavigationAgents see Using NavigationAgents.
Agent avoidance helps to prevent direct collision with other agents or moving obstacles while the agents still follow their original velocity as best as possible.
Avoidance in Godot is implemented with the help of the RVO library (Reciprocal Velocity Obstacle).
RVO places agents on a flat RVO map and gives each agent a
radius and a
Agents with overlapping radius compute a
safe_velocity from their
safe_velocity then needs to replace the original
velocity to move the actor behind the agent with custom movement code.
RVO avoidance is not involved in regular pathfinding, it is a completely separate system. If used inappropriately, the RVO avoidance can actively harm the perceived pathfinding quality.
Creating Avoidance Agents with Scripts¶
Agents and obstacles share the same NavigationServer API functions.
Creating agents on the NavigationServer is only required for avoidance but not for normal pathfinding. Pathfinding is map and region navmesh based while avoidance is purely map and agent based.
extends Node3D var new_agent_rid: RID = NavigationServer3D.agent_create() var default_3d_map_rid: RID = get_world_3d().get_navigation_map() NavigationServer3D.agent_set_map(new_agent_rid, default_3d_map_rid) NavigationServer3D.agent_set_radius(new_agent_rid, 0.5) NavigationServer3D.agent_set_position(new_agent_rid, global_transform.origin)
To receive safe_velocity signals for avoidance for the agent a callback needs to be registered on the NavigationServer.
extends Node3D var agent_rid: RID = NavigationServer3D.agent_create() NavigationServer3D.agent_set_callback(agent_rid, self.on_safe_velocity_computed) func on_safe_velocity_computed(safe_velocity: Vector3): # do your avoidance movement
After the current and new calculated velocity needs to be passed to the NavigationServer each physics frame to trigger the safe_velocity callback when the avoidance processing is finished.
func _physics_process(delta): NavigationServer3D.agent_set_velocity(current_velocity) NavigationServer3D.agent_set_target_velocity(new_velocity)
If _process() is used instead of _physics_process() at a higher framerate than physics the agent velocity should not be updated more than ones each physics frame e.g. by tracking the Engine.get_physics_frames().