Weird enemy AI NavAgent

Godot Version

Godot 4.2

Question

Hello! I am having a problem with my basic enemy, where for now, he just needs to follow the player. As i was testing a code that i got from a youtube tutorial (Channel: LegionGames) to help me with this matter, after everything done, the enemy tries to catch the player, but when he finally gets to the player position, he just…starts flying? Going nowhere also, just catches flight and disappears into the horizon.

Another problem is that he doesn’t really go to the player position, after i changed the player’s position to a new one, the enemy followed that same path as before, so maybe he doesn’t try to catch the player at all?

I don’t know what im doing wrong…below are some screenshots and the code i used:

(wish i could post more images, sorry)

~~The enemy’s code:

extends CharacterBody3D

var player = null

const SPEED = 3.0

@export var player_path : NodePath
@onready var nav_agent = $NavigationAgent3D as NavigationAgent3D

func _ready():
player = get_node(player_path)

func _process(delta):
velocity = Vector3.ZERO #the line right below is the problem
nav_agent.target_position = player.global_transform.origin
var next_nav_point = nav_agent.get_next_path_position()
velocity = (next_nav_point - global_transform.origin).normalized() * SPEED
move_and_slide()

Also, if anyone has a better way or a better tutorial on how i can do enemy AI (a simple one, doesn’t have to be too crazy, even if it’s just the enemy following) i’d really appreciate. This is giving me headaches already

I can’t see anything from the screenshots. :frowning:

I recommend reading the docs: Using NavigationAgents — Godot Engine (stable) documentation in English

At the bottom there a 3 script examples for navigation (Node3D, Rigidbody3D and CharacterBody3D). They worked pretty good for me.

Thanks to your feedback, i now updated the image shown and it should be clearer to see where the enemy is.

Also, if anyone want to see more of the enemy, i have more screenshots, such as this one that could show the level of my problem:

You can BARELY see it, but there’s a tiny black dot there by the sky, which i’m looking at. Yeah, and he doesn’t stop there, he just goes on

You are using the frame rate depending _process() function for a physics object, that does not work, use the stepped _physics_process() function.

changed _process to _physics_process, and it did the same thing as before :frowning:

Please use one of the agent script templates from the documention first to confirm that your node setup is even working. Using NavigationAgents — Godot Engine (latest) documentation in English

If those scripts that are known to be working do not solve the issue it is likely caused by how you setup your nodes and physics collision. The pathfinding on navigation mesh is not even technically able to make your agents float like that, at all, but if you setup collision in a way that every step the agent velocity pushes and slides it upward you agent will go to space.

ooh, got it now, thanks! I actually am using it right now and it seems the bug stopped happening. The enemy now isn’t moving anymore, but atleast i have a canvas to work better on. If i could use any more help, how could i tweak the script to make the enemy chase the player? i tried adding some things from the old script (the one that i was using for the enemy), which seemed most logical, but the enemy still stays put.


extends CharacterBody3D

var player = null#i added this

@export var player_path : NodePath#this one also
@export var movement_speed: float = 4.0
@onready var navigation_agent: NavigationAgent3D = get_node("NavigationAgent3D")

func _ready() -> void:
	player = get_node(player_path)#this one
	navigation_agent.velocity_computed.connect(Callable(_on_velocity_computed))

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 = player.global_position.direction_to(next_path_position) * movement_speed#and changed this one to add "player" before "global"
	if navigation_agent.avoidance_enabled:
		navigation_agent.velocity = new_velocity
	else:
		_on_velocity_computed(new_velocity)

func _on_velocity_computed(safe_velocity: Vector3):
	velocity = safe_velocity
	move_and_slide()

if you didn’t see, i also added “player” before “global_transform”

All you need to do is occasionally (not every frame, use a timer or distance check) set the navigation_agent.target_position to your player.global_position.

The velocity calculation in your changed code makes no sense atm and should be reverted. The direction vector from your player’s global position to your path global position is not a valid velocity on top of going in the wrong direction.

I just want to say that this original post made me lol. This is the story of my game dev life…the ____ does ___ then…it just flies off into the universe!!! LOL I am so glad you got the help you needed, though :slight_smile:
I agree with smix8 that it is best to not put things in physics process or process unless TRULY should be checked in every frame.