Semaphore or other way to tell NPC's who goes first

Godot Version

4.7.1

Question

I have started working on this simple Adventure RPG Game and came across the Navigation issue.

When Multiple NPC’s are placed and wants to go random places it quite tricky when one get behind the other one, they won’t seek alternative route around. Is there some setting in NavigationAgent3D which I could use to make them wait or go around to avoid blocking each other?

Short video demo

Project is placed in this post Portal Ranger - 3D Adventure Game with repository.

It’s build out of components so posting exactly relevant code would be

Finding valid random point on nav_mesh

class_name NPCWanderComponent extends Node

@export var nav_agent: NavigationAgent3D

var _nav_regions: Array[NavigationRegion3D] = []

func _ready() -> void:
	for node in get_tree().get_nodes_in_group("nav_regions"):
		if node is NavigationRegion3D:
			_nav_regions.append(node)
	_pick_new_target()
	nav_agent.navigation_finished.connect(_pick_new_target)

func _pick_new_target() -> void:
	if _nav_regions.is_empty():
		return
	var region: NavigationRegion3D = _nav_regions.pick_random()
	var point := NavigationServer3D.region_get_random_point(region.get_rid(), 1, false)
	nav_agent.target_position = point

and

turn this into move_dir( which is repurposed from Player Input used WASD to do it )

class_name NPCInputComponent extends InputComponent

@export var nav_agent: NavigationAgent3D
@export var body: Node3D

func update() -> void:
	if nav_agent == null or body == null:
		return
	if nav_agent.is_navigation_finished():
		move_dir = Vector2.ZERO
		return
	var next_pos := nav_agent.get_next_path_position()
	var to_target := next_pos - body.global_position
	move_dir = Vector2(to_target.x, to_target.z).normalized()

Scene tree

NavigationAgent properties

I think that selecting “Use 3D Avoidance” alone is not enough. You have to do something in code. Using Agent Avoidance — Godot Engine (4.0) documentation in English

I see there could be potentially used velocity_computed signal, but part of documentation not making entirely sense to me

Set the velocity of the NavigationAgent node in _physics_process() to update the agent with the current velocity of the agent’s parent node.

Do I use signal to get velocity but is this somehow will be aware of other agents?

Simple project made but can’t find solution to it.

Used basic script form docs to use

navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))

Tried to make Area3D to detect other bodies and change their agent.avoidance_priority to random number.

func _on_my_space_body_entered(body: Node3D) -> void:
		navigation_agent.avoidance_priority = randf()

Tinkered with Agent Pathfinding values and Avoidance values, but couldn’t find sweet spot to make NPC use both ways, and stop from blocking each other.

NPC scene_tree

Level_Scene overview

Full code and project are included on Github, it’s minimalistic project.

I think about solution like have semaphore on in sense of only one direction is allow at the time.

So bottom NPC’s could go through green_passage from bottom to top, and top npc go via red_passage, but how would I keep track of it?

Here is some footage from using just basic’s on editor and standard code

Have tried use Area3D, small script to detect travel_direction but this still caused chaos :slight_smile: .

Maybe some manual layer adjustments.

Would appreciate any help.

trouble with checking travel direction is when target is at area where player should go from other way but NavigationServer calculated it from opposite Z direction, is there maybe way to add custom rules along different NavigationLayers ?