Navigation Target Reached Signal not Firing

Godot Version

Godot_v4.3-stable_win64

Question

How can I make sure the target_reached signal fires so I can execute a function once the player and enemy collide?

For reference I used this tutorial to set up the enemy character’s movement via a navigation agent. Around ‘7:42’ (link should go to this timestamp) he sets up the “target_reached()” signal :

In my project for some reason the signal never fires even though the enemy is colliding with my player. I’ll show some screenshots and add the scripts of the enemy and the main level we’re testing in for context below!

The main level, enemy colliding with player but no signal from the target_reached function is printed as I have it set to do from my enemy script :

func _on_navigation_agent_3d_target_reached():
	print("Cooper reached!")

I do see this error though when running and I’m wondering if this is causing the problem, possibly? :

E 0:00:01:0102   doppelganger.gd:11 @ _physics_process(): NavigationServer navigation map query failed because it was made before first map synchronization.
	NavigationServer 'map_changed' signal can be used to receive update notifications.
	NavigationServer 'map_get_iteration_id()' can be used to check if a map has finished its newest iteration.
  <C++ Source>   modules/navigation/nav_map.cpp:141 @ get_path()
  <Stack Trace>  doppelganger.gd:11 @ _physics_process()

I was reading it could be caused by frame issues and running navigation set up in the ready function but mine runs in the physics_process_delta function within my main level scene :

extends Node3D

@onready var Cooper = $Cooper

func _physics_process(delta):
	get_tree().call_group("Enemies", "_update_target_location", Cooper.global_transform.origin)

This is the main level with a navigation mesh attached to the floor, along with the node tree.



Here is the enemy called the “Doppelganger” scene, node tree and script.

extends CharacterBody3D

@onready var NavAgent = $NavigationAgent3D
@onready var DS_AP = $DoppelgangerSkin/AnimationPlayer
@onready var DS : Node3D =  %DoppelgangerSkin

@export var move_speed = 8

func _physics_process(delta):
	var current_location = global_transform.origin
	var next_location = NavAgent.get_next_path_position()
	var new_velocity = (next_location - current_location).normalized() * move_speed
	
	velocity = velocity.move_toward(new_velocity, .25)
	move_and_slide()
	DS.look_at(next_location)
	DS.rotate_object_local(Vector3.UP, PI)
	DS_AP.play("Walk002")
	

func _update_target_location(target_location):
	NavAgent.set_target_position(target_location)


func _on_navigation_agent_3d_target_reached():
	print("Cooper reached!")

Thanks for reading! The only issue I can think of is using box shapes instead of capsule shapes like the tutorial but for some reason they have just tended to work better for me.

1 Like

I think the NavAgent node is using it’s own relative position to check for that, I would try tweaking the desired distance in the NavAgents’s pathfinding settings.

Since both entities have their own hitboxes, it’s possible that the NavAgent never gets within 1m of the target…

1 Like

I think vonpanda might be on the right track of the actual issue.

The error message that you get might be unrelated. It may be triggered because your Doppelganger is doing a nav query before the server is ready. You should await at least one physics frame before accessing it:

func _ready():
	# Make sure to not await during _ready.
	actor_setup.call_deferred()

func actor_setup():
	# Wait for the first physics frame so the NavigationServer can sync.
	await get_tree().physics_frame

	# Now that the navigation map is no longer empty, and you can start working with path setup and stuff.

Source (very bottom of the page): Übersicht 3D-Navigation — Godot Engine (4.x) Dokumentation auf Deutsch

2 Likes

Thank you so much this was it! I only had to move the “Target” Setting up! Now just need to tweak for the perfect distance!

1 Like

It does appear to be unrelated, I’ll try adding this to my script!
Thank you!

Edit :

Just for reference in case anyone stumbles on this thread,
Changed my Main Level Script to this instead and the error is gone.

extends Node3D

@onready var Cooper = $Cooper

func _ready():
	_actor_setup.call_deferred()

func _actor_setup():
	await get_tree().physics_frame
	get_tree().call_group("Enemies", "_update_target_location", Cooper.global_transform.origin)

func _physics_process(delta):
	pass