Strange navigation agent behaviour

Godot Version

4.2.2

Question

Not sure if this comes across on the video. I have a basic scene, with a NavigationRegion but when I navigate around the terrain the movement jitters/slows down when the player crosses a navigation polygon. I followed the documentation Godot has here:

At first I thought it may have been something to do with how I set up my character. So I tried it with a basic CharacterBody3D with a capsule and the same problem occurs (little harder to see.)

With player:

With test:

Not sure what it could be. I’ve tried changing the navigation mesh to reduce the number of nav polygons. I have also tried tweaking the pathfinding properties of the agent in “Path Desired Distance” etc but no joy.

extends CharacterBody3D

@export var movement_speed: float = 8.0
@onready var camera: Camera3D = get_node("Camera3D")
@onready var navigation_agent: NavigationAgent3D = get_node("NavigationAgent3D")

func _ready() -> void:
	navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))
	

func _input(event):
	if event is InputEventMouseButton and event.is_action_pressed("move"):
		var result = _mouse_raycast()
		if !result: return
		
		set_movement_target(result.position)


func set_movement_target(movement_target: Vector3):
	navigation_agent.set_target_position(movement_target)

func _physics_process(delta):
	if navigation_agent.is_navigation_finished():
		return

	var next_path_position: Vector3 = navigation_agent.get_next_path_position()
	var new_velocity: Vector3 = global_position.direction_to(next_path_position) * movement_speed
	if navigation_agent.avoidance_enabled:
		navigation_agent.set_velocity(new_velocity)
	else:
		_on_velocity_computed(new_velocity)

func _on_velocity_computed(safe_velocity: Vector3):
	velocity = safe_velocity
	move_and_slide()
	
func _mouse_raycast():
	var mouse_position = get_viewport().get_mouse_position()
	var from = camera.project_ray_origin(mouse_position)
	var to = from + camera.project_ray_normal(mouse_position) * 1000
	var space_state = get_parent().get_world_3d().direct_space_state
	
	var params = PhysicsRayQueryParameters3D.new()
	params.from = from
	params.to = to
	
	var result = space_state.intersect_ray(params)
	return result

Try without avoidance and / or physics collision.
If it does not “jitter” with disabled avoidance disable the “keep_y_velocity” property.
If it does not “jitter” with physics disabled your collision shape / gravity / new_velocity calculation is the problem.

Make sure that the agent parent nodes global position and the navigation mesh can actually reach each other. You can apply a general path_height_offset value if that is too difficult to manage with the node setup. In any case make sure that your collision shape never gets in the way of those two positions. They need to be able to reach each other and also target each other without needing a direction that goes in the ground or air. If your velocity aims in the ground + gravity when path points are close your collision shape alone might slow everything down.

1 Like

Smix, thank you so much!
I followed your suggestions, I temporarily disabled the CollisionBody and it worked.

I didn’t fully understand what you meant with the parent nodes global position and navigation mesh. Do you mean if the navigation mesh is it at Y = 0 and the parent node is fixed at Y = 1 it could’ve caused this issue?

Regardless, changing the path_height_offset fixed it.
Really appreciate your help, thanks again.

A navigation mesh always hovers on its source geometry surface. In order to increase the path index to the next path point the agent parents global position needs to get into the desired distance of that path global position.

If collision shapes block this the path index can never get increased and the agent gets stucked. If the agent parent is very much on top or below the path point a naive calculated direction vector might aim in the ground or in the air. In this case the horizontal velocity will be minimal because the majority of the velocity goes along the y-axis that is ignored by the 2d avoidance and that is why things might slow down.

Understood. This makes sense now. Thank you for explaining and appreciate the help.