Characters stucked outside the navmesh

Godot Version

4.5.1

Question

Hello everyone!

I have a problem I can’t seem to solve: I have characters that follow the player. When they get too close together around the player, some are pushed out of the navmesh. As a result, the characters can no longer move. I use the “avoidance” system on my characters’ NavigationAgent2D to prevent them from stepping on each other.

Here is the navmesh:

The settings:

And this is when the characters surround the player and how some of them end up outside the navmesh.

If anyone has any ideas on how to avoid this “push” effect outside of the navmesh, that would be great. Thanks in advance.

PS: Here’s the code that allows my characters to move

func _ready() -> void:
	add_to_group("enemies")
	
	if fov:
		fov.seen.connect(_on_character_detected)
	
	if navigation_agent and navigation_agent.avoidance_enabled:
		navigation_agent.velocity_computed.connect(_on_safe_velocity)
		navigation_agent.max_speed = chase_speed

func _on_safe_velocity(safe_velocity: Vector2) -> void:
	position += safe_velocity * get_physics_process_delta_time()
	set_direction()

func move(speed: float, _delta: float) -> void:
	if navigation_agent.is_navigation_finished():
		return
	
	var next_path_position: Vector2 = navigation_agent.get_next_path_position()
	var new_velocity = global_position.direction_to(next_path_position) * speed
	
	if new_velocity.length() < 1.5:
		navigation_agent.velocity = Vector2.ZERO
		return
	
	if navigation_agent.avoidance_enabled:
		navigation_agent.velocity = new_velocity
	else:
		_on_safe_velocity(new_velocity)

I think you can use NavigationServer2D’s map_get_closest_point()-method to try to get them back in.

You just have to realize when they are outside, probably by checking the next path position and then take the closest point as new destination

Or do you not want them getting kicked out in the first place? in this case i think physics are the only way to stop them, or reduce the avoidance between your entities

Thanks! I just added a check during character movement and it seems to be working.

I’m still looking for a native way to prevent this from happening.

func is_on_navmesh() -> bool:
	var map: RID = NavigationManager.map
	var closest: Vector2 = NavigationServer2D.map_get_closest_point(map, global_position)
	return global_position.distance_to(closest) < 10.0
	
func snap_back_to_navmesh():
	var map: RID = NavigationManager.map
	var nav_pos: Vector2 = NavigationServer2D.map_get_closest_point(map, global_position)

	global_position = nav_pos
	navigation_agent.set_target_position(navigation_agent.target_position)
	
func _on_safe_velocity(safe_velocity: Vector2) -> void:
	position += safe_velocity * get_physics_process_delta_time()
	
	if not is_on_navmesh():
		snap_back_to_navmesh()
		return

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.