My pathfinding is broken

Godot Version

4.4.1 Stable

Question

I have my pathfinding AI that uses a function to find a random point on the navmesh and pathfind there. the issue is that it randomlhy stopped working and im not sure what changed. the problem is that when it reaches the target, it is supposed to stop moving and pick a new pathfinding point, but instead it freezes in place but continues playing the walking animation and doesn’t continue pathfinding. i used a print(velocity) function to debug and it says that there is constant force of -2.5 on the Y axis but there is no gravity. here is where it gets very weird: 2.5 is the speed that it pathfinds at when it is not chasing the player, but for some reason it get applied to the Y axis. i have looked at the collision shapes and it is not getting stuck on anything. I have no idea what to do.

I think you’ll need to post some code if we’re going to be able to help.

If you post it like this:

```gdscript
code
code
code
```

It will come out like this:

code
code
code

dont ask about the shrek stuff im making a shrek horror game

extends CharacterBody3D


const JUMPSCARE = preload("res://scenes/jumpscare.tscn")
const JUMPSCARE_3_AM = preload("res://scenes/jumpscare3am.tscn")
var played_sound = false
var navregionpositions = null
var player = null
var SPEED = 5.0
const JUMP_VELOCITY = 4.5
var hunting = false
var mobile = true
@onready var nav_agent: NavigationAgent3D = $NavigationAgent3D
@export var player_path : NodePath
@export var toggle : bool = false

func _ready():
	randomize()
	player = get_node(player_path)
	navregionpositions = $"../NavigationRegion3D".navigation_mesh.get_vertices()
	pick_random()




func pick_random():
	if navregionpositions.size() > 0:
		var randomindex = randi() % navregionpositions.size()
		var local_point = navregionpositions[randomindex]
		var nav_map = nav_agent.get_navigation_map()
		pathfind(local_point)
		print("Going to navmesh point:", local_point)
	else:
		print("navregionpositions is empty!")





func _physics_process(delta: float) -> void:
	velocity = Vector3.ZERO
	
	# At the top of _physics_process
	if not is_on_floor():
		velocity.y -= 9.8 * delta
	else:
		velocity.y = 0

	
	
	if Input.is_action_just_pressed("shreksophone"):
		shreksophone()
	
	
	if mobile:
		if hunting:
			if not $sounds/chasemusic.playing:
				$sounds/chasemusic.play()
			SPEED = 4.5
			pathfind(player.global_transform.origin)
			$model/Skeleton3D/LookAtModifier3D.active = true
		else:
			$sounds/chasemusic.stop()
			played_sound = false
			SPEED = 2.5
			$model/Skeleton3D/LookAtModifier3D.active = false
		
		
		
		var next_nav_point = nav_agent.get_next_path_position()
		var direction = next_nav_point - global_transform.origin
		velocity = direction.normalized() * SPEED
		
		
		
		
		
		
		if nav_agent.is_target_reached():
			velocity = Vector3.ZERO
			if $"timers/look around".is_stopped():
				$"timers/look around".start()
			
			if $timers/waitafterpathfind.is_stopped():
				$timers/waitafterpathfind.start()
		else:
			var target = Vector3(next_nav_point.x, global_position.y, next_nav_point.z)
			if global_position.distance_to(target) > 0.01:
				look_at(target, Vector3.UP)
		
		
		
		
		if velocity != Vector3.ZERO:
			if hunting:
				$model/AnimationPlayer.play("Drunk Run Forward/mixamo_com")
			else:
				$model/AnimationPlayer.play("Drunk Walk/mixamo_com")
		else:
			$model/AnimationPlayer.play("idle/mixamo_com")
		
		for overlap in $deathtrigger.get_overlapping_bodies():
			if overlap.name == "Character":
				if mobile:
					if Time.get_time_dict_from_system()["hour"] == 3:
						get_tree().change_scene_to_packed(JUMPSCARE_3_AM)
					else:
						get_tree().change_scene_to_packed(JUMPSCARE)
		
		print(velocity)
		move_and_slide()





func _on_visiontimer_timeout() -> void:
	if toggle:
		if mobile:
			var overlaps = $"field of view".get_overlapping_bodies()
			if overlaps.size() > 0:
				for overlap in overlaps:
					if overlap.name == "Character":
						$"field of view/visionraycast".look_at(overlap.global_position, Vector3.UP)
						if $"field of view/visionraycast".is_colliding():
							if $"field of view/visionraycast".get_collider().name == "Character":
								hunting = true
								$timers/chasetimer.start()
								playchasesound()


func pathfind(point : Vector3):
	$NavigationAgent3D.set_target_position(point)



func _on_waitafterpathfind_timeout() -> void:
	pick_random()


func immobile(time):
	$model/Skeleton3D/shreksophone.hide()
	$sounds/shreksophone.stop()
	$hitbox.disabled = true
	mobile = false
	$timers/immobile.wait_time = time
	$timers/immobile.start()
	$model/AnimationPlayer.play("Zombie Death/mixamo_com")



func _on_chasetimer_timeout() -> void:
	print("lost player")
	hunting = false
	pick_random()


func shreksophone():
	$timers/immobile.stop()
	$sounds/whatareyoudoinginmyswamp.stop()
	$sounds/chasemusic.stop()
	$sounds/shreksophone.play()
	pathfind(position)
	$hitbox.disabled = false
	hunting = false
	mobile = false
	$model/AnimationPlayer.play("Wave Hip Hop Dance/mixamo_com")
	$model/Skeleton3D/shreksophone.show()



func playchasesound():
	if played_sound == false and $sounds/whatareyoudoinginmyswamp.playing != true:
							played_sound = true
							$sounds/whatareyoudoinginmyswamp.play()


func _on_immobile_timeout() -> void:
	$hitbox.disabled = false
	
	mobile = true


func _on_shreksophone_finished() -> void:
	mobile = true
	$model/Skeleton3D/shreksophone.hide()


func _on_look_around_timeout() -> void:
	rotate_y(randi_range(-45,45))


i sent the code

My advice would be first to stick a bunch of printing in, or better yet, put a UI label somewhere on the screen that you can scribble on. You need some context as to what’s happening and when.

It could be that something is wrong with your navigation logic. It could be that something is wrong with your timer logic. There are a variety of things that could be going wrong here.

The trick is to print stuff out so you know what is happening and what the code thinks it’s doing.

For example, I’d probably do something like:

		if nav_agent.is_target_reached():
			print("Target reached!")
			velocity = Vector3.ZERO
			if $"timers/look around".is_stopped():
				print("Starting look around timer.")
				$"timers/look around".start()
			else:
				print("Look around timer already running.")
			if $timers/waitafterpathfind.is_stopped():
				print("Starting wait after pathfind timer.")
				$timers/waitafterpathfind.start()
			else:
				print("Wait after pathfind timer already running.")

And so forth. It’ll be spammy, but I bet you find things aren’t quite in the state you thought they were…

You might also want to look at mobile; it seems to lock out a lot of stuff when it’s false, including some of your state maintenance logic.

i might have found the issue
the cube is where it was given direction to go to


my pick_random function chooses a random vertice on the navmesh and tells the AI to pathfind there, but its not on the navmesh???

I kind of think you wouldn’t want a vertex anyways; presumably you want to be in the middle of one of the nav polygons, not at one of the corners.

I think you want to pick a triangle from the mesh.

how could i do that? im not too great with that kinda stuff

I think you should be able to call get_faces() instead of get_vertices(), and you’ll get back an array where each entry is a vertex, and they’re in groups of three (so the array length should be a multiple of three…), with each group of three being a triangle. Average those positions and you should be near the middle of your nav mesh triangle.

Invalid call. Nonexistent function 'get_faces' in base 'NavigationMesh'.

Ah, there’s get_polygon(index) and get_polygon_count(). So, use _count() to figure out which one to randomly grab. get_polygon() gets you an array of indexes for vertices, so you’ll need to march the list pulling vertices from get_vertices() and then average those.

it is better, but it still does not solve the issue with the AI

also does this look correct to you?

func pick_random():
	if navregionpolygons > 0:
		var navregion = $"../NavigationRegion3D"
		var navmesh = navregion.navigation_mesh
		var randomindex = randi() % navregionpolygons
		var polygon_vertices = navmesh.get_polygon(randomindex)
		var vertices = navmesh.get_vertices()
		
		var vertice1 = vertices[polygon_vertices[0]]
		var vertice2 = vertices[polygon_vertices[1]]
		var vertice3 = vertices[polygon_vertices[2]]
		var vertice_sum = vertice1+vertice2+vertice3
		var vertice_average = vertice_sum / 3
		var local_point = vertice_average
		pathfind(local_point)
		print("Going to navmesh point:", local_point)
		$"../pathfindmarker".position = local_point
	else:
		print("navregionpositions is empty!")

Ish? Though you may find some of the polygons are more than three vertices.

ok but my ai is still broken
here is a video
the ai is shrek because my friend told me to make a shrek horror game

For the broken AI, I suggest printing out each decision it makes, and see if you can spot where it goes wrong.

ok thanks for the help

I found it the NavigationAgent3D.target_desired_distance was too low. thanks for the help

1 Like

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