Need help figuring out what my enemy navigation script is missing

Godot Version

4.1.3

Question

I recently started working with Godot after experimenting with Minecraft Bedrock’s addon system for some time and finding it unsatisfactory for my purposes. i’ve built a player with good movement and am working on a basic enemy movement script which can be reused across many types of enemies. Right now, I have an enemy scene with a CharacterBody2D as the root and the bulk of the enemy code in a script attached to the body (enemy.gd); this script receives signals from another script attached to an Area2D (aggro_zone.gd) whenever another body enters or leaves its radius. These signals are connected by a function in enemy.gd and used to switch between pursuit states in order to restrict pathfinding behavior to within the aggro zone’s area. What actually happens is that the enemy stays in place until the player walks directly in front of them, and then essentially sticks to the player until the player dislodges the enemy by scraping them off on a piece of terrain.

This is the relevant code from enemy.gd:

extends CharacterBody2D

var pursuing = false

@export var speed = 100
@onready var player = Player
@onready var nav_agent = $nav_agent
@onready var aggro_zone = $aggro_zone

func _ready():
	makepath()

func _physics_process(_delta:float) -> void:
	var dir = to_local(nav_agent.get_next_path_position()).normalized()
	velocity = dir * speed
	move_and_slide()

func on_timer_timeout():
	makepath()
	connect("entered_aggro_range", self.set_pursuit_mode())
	connect("left_aggro_range", self.set_pursuit_mode())

func makepath() -> void:
	if pursuing == true:
		nav_agent.target_position = player.global_position

func set_pursuit_mode():
	if pursuing == false:
		pursuing = true
		print("You're mine!")
	elif pursuing == true:
		pursuing = false

And this is the relevant code for the aggro zone script:

extends Area2D

signal entered_aggro_range
signal left_aggro_range

func _on_aggro_zone_body_entered(_body):
	emit_signal("entered_aggro_range")

func _on_aggro_zone_body_exited(_body):
	emit_signal("left_aggro_range")

I have a single testing scene with a tilemap, instantiated player scene and several instantiated enemies all as children of the root Node2D. I have tried numerous schemes for organizing this code and this is one of a few that throws me no errors. My goal is to have the enemy begin chasing the player when they enter the aggro_zone.

I have been staring at my computer for days trying to sort this out. I’m certain there’s a glaring omission I’m just not seeing because i’m not used to the engine yet, and i’d be forever indebted to anyone who can help me get my guys moving and chasing down my player. Thanks in advance.

It doesn’t look like this function gets called, to then call makepath that sets up the pursuit path.

and this makepath() function in _ready is only called once when the enemy is created. which the persuing bool is false so it never changes the nav_agent.

Basically you never tell your nav agent the news… it also seems like the signals are never connected.

I solved the problem. I was being silly.

I know the timer function was being called successfully because i added a print() to it, and it printed once per second like it should have. The problem I had was twofold:

  1. I was trying to get the position of the Player script class i made instead of the actual node, and since a script doesn’t have a position, of course that failed. I solved this by calling %player instead.

  2. I had neglected to center the position of the root player node on the rest of the player’s children including the sprite, so while the player sprite was in the play area as it should have been, the player root global position was way out to the upper left. I solved this by simply aligning all the children with the center of the player root.

I did also remove makepath() from _ready() because that was silly.

Your comment prompted me to take a closer look at my code and that helped me solve the problem. Thank you very much.