Godot Version
Godot 4.6
Question
I’m trying to make a new Enemy AI system from scratch and so far I’ve made a bit of progress, its supposed to patrol between 3 locations (represented by the selected node’s position, which are the exported variables in the script) and so far I managed to make it go to one location, but then it just stopped moving and not go to the other 3 locations, how do I fix this and why did this happen?
For more detail I’m using a NavigationAgent2D with Avoidance.
extends CharacterBody2D
@export var object1: Node2D
@export var object2: Node2D
@export var object3: Node2D
@onready var nav_agent: NavigationAgent2D = $NavigationAgent2D as NavigationAgent2D
var speed: int = 600
func _ready() -> void:
nav_agent.velocity_computed.connect(_on_navigation_agent_2d_velocity_computed)
func _physics_process(delta: float) -> void:
patrol()
func _on_navigation_agent_2d_velocity_computed(safe_velocity: Vector2) -> void:
velocity = safe_velocity
move_and_slide()
func patrol():
var dir = to_local(nav_agent.get_next_path_position())
var intend_velocity = dir * speed
var current_position = object1.global_position
nav_agent.target_position = current_position
nav_agent.velocity = intend_velocity
print(current_position)
print(velocity)
if nav_agent.is_target_reached():
current_position = object2.global_position
nav_agent.get_next_path_position()
print(current_position)
print(velocity)
It appears that in patrol() you override the changes made to current_position that occur if nav_agent.is_target_reached() returns true.
So When it reaches the target position, the enemy would get stuck in a loop where each frame it updates current_position from object1.global_position to object2.global_position, then reverts this at the start of the next frame.
My solution to this would be using an iterator and an array to switch the object you’re referencing. Something like this:
extends CharacterBody2D
@export var object1: Node2D
@export var object2: Node2D
@export var object3: Node2D
@onready var nav_agent: NavigationAgent2D = $NavigationAgent2D as NavigationAgent2D
var speed: int = 600
#Lines below are added
var target_array: Array = [object1,object2,object3]
var next_target: int = 0
func _ready() -> void:
nav_agent.velocity_computed.connect(_on_navigation_agent_2d_velocity_computed)
func _physics_process(delta: float) -> void:
patrol()
func _on_navigation_agent_2d_velocity_computed(safe_velocity: Vector2) -> void:
velocity = safe_velocity
move_and_slide()
func patrol():
var dir = to_local(nav_agent.get_next_path_position())
var intend_velocity = dir * speed
#Line below is changed
var current_position = target_array[next_target].position
nav_agent.target_position = current_position
nav_agent.velocity = intend_velocity
print(current_position)
print(velocity)
#if statement has been changed, new one added
if nav_agent.is_target_reached() && next_target <= target_list.size() - 1:
#current_position = object2.global_position
next_target += 1
nav_agent.get_next_path_position()
print(current_position)
print(velocity)
if next_target >= target_list.size() - 1:
next_target = 0
I don’t have your setup so I can’t test this code myself, so I can’t be 100% sure it will work. What I’ve essentially done is moved the code for changing current_position into the third line of patrol(), made an array to hold the list of objects, and made the if statement select which object is being referenced in this list. If this method has errors, I can help fix those, but I would need you to test it on your end.