For the past month or so I have been trying to get my NPC AI into a working state. I am awfully bad at this. I feel I’ve made some fundamental mistake in how I’ve designed my code that makes it very difficult to get working, or otherwise have some critical error that prevents it from working properly. I have made some improvements, for example it actually wanders through waypoints properly (ironically all it took was a check to see if it already has a path), but it’s still far from working even in a simple state. It will navigate along the path to each checkpoint, and when the player is in sight will chase them, but quickly stops. It appears to be related to the for loop through the table of waypoints, continuing through the for loop even as the attack function should be running, due to the outputs below:
Another long-term issue I’ve been trying to solve is getting the AI to go back to wandering in a non-janky way after the player is dead/out of sight, without paths beginning to overlap.
As for what I’ve tried, I’ve taken a look at a couple of other AIs I’ve seen as well as some video tutorials, however outside of not wanting to straight up lift other people’s code I also believe that for what I plan to build onto the AI their structures may not work or be ideal (such as slowly navigating to the player’s location and searching for them if they’re in the room or have just been lost). I’m willing to swallow my pride though if there’s a tutorial that just works really well for this.
tl;dr AI stops chasing randomly and also doesn’t go back to wandering around and chasing the player on sight after player dies/is out of sight, I’m super tired of working on this and would like to know what I’ve done wrong.
I’ve taken the liberty of removing the functions that I believe work properly and have nothing to do with the issue, but I can send them if needed.
local function attack(target)
local plrChar = target.Character
if plrChar then
local plrHum = plrChar:WaitForChild("Humanoid")
local plrHRP = plrHum.RootPart
lastKnownTargetPos = plrHRP.Position
hum.WalkSpeed = ai_run_speed
hum:MoveTo(lastKnownTargetPos)
print("Attacking "..plrChar.Name)
local dir = plrHRP.Position - hrp.Position
local attackRay = workspace:Raycast(hrp.Position, dir, params)
if attackRay then
if attackRay.Instance:IsDescendantOf(plrChar) and plrHum.Health > 0 then
if attackRay.Distance < ai_attack_range then
plrHum.Health = 0
hum.WalkSpeed = ai_walk_speed
end
else
print("Searching")
hum.WalkSpeed = ai_walk_speed
hum:MoveTo(lastKnownTargetPos)
hum.MoveToFinished:Wait()
hasPath = false
end
end
end
end
local function moveToPosition(position)
print(hasPath)
if hasPath == false then
local path = getPath(position)
local success, errorMessage = pcall(function()
path:ComputeAsync(hrp.Position, position)
end)
if success and path.Status == Enum.PathStatus.Success then
hasPath = true
print("Moving to "..position.X..", "..position.Y..", "..position.Z)
waypoints = path:GetWaypoints()
for i, waypoint in pairs(waypoints) do
local part = Instance.new("Part")
part.Parent = workspace
part.Position = waypoint.Position
part.BrickColor = BrickColor.new("Lime green")
part.CanCollide = false
part.Anchored = true
part.Shape = Enum.PartType.Ball
game.Debris:AddItem(part, 10)
end
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
blockedConnection:Disconnect()
moveToPosition(position)
end)
table.remove(waypoints, 1)
for i, waypoint in pairs(waypoints) do
print(i)
local target = getTarget()
if target and target.Character.Humanoid.Health > 0 then
attack(target)
else
hum:MoveTo(waypoint.Position)
hum.MoveToFinished:Wait()
if i == #waypoints then
hasPath = false
end
end
end
end
end
end
local function wander()
local patrolPoint = mapWaypoints[math.random(1, #mapWaypoints)]
moveToPosition(patrolPoint.Position)
end
while task.wait(0.01) do
wander()
end