A while ago, I changed the zombies' AI in my game, Zombie Attack, from the drooling zombie's AI to a more basic one, the old findnearesttorso AI used in many zombie models. Most of the maps I've made for the game are an open area with no walls, (excluding the borders of the map) but I've started work on a map with multiple buildings to explore. Since the zombies only move to your position, they can get stuck on walls, and ultimately, the game would take longer to finish because players would spend all their time finding where all the zombies were piled up at. So recently, I've decided to give pathfinding a try, and it works! Well, mostly. The zombies do find a path to you, and they follow that path, but they will stick to that path for the rest of the time it takes them to get there. That presents 2 problems. Even if the player moves, the zombie will continue following the current path, and won't create a new one if the player strays too far from the end of the path, which can make it seem like the zombie is chasing nothing. The other problem is if something moves in front of the zombie, whether it's a wall (extremely unlikely) or another zombie. (eh, it could happen) The zombie will get stuck on this and never make it to the next point of their path, pretty much making the zombie cannon fodder for whoever gets to it first. The wiki says to use CheckOcclusionAsync
, but it's not very descriptive on how it works, and I'm pretty much lost on that part.
Anyways, here's my code. Please tell me what I can do to fix this, or at least help me out on it. Thanks! (I got the pathfinding parts from the wiki, since I was pretty much clueless on how to use pathfinding prior to this.)
My best guess for a solution to problem #1 is to detect whether or not the player's position is the same as the final point on the path's position, then use return
to restart the loop and find a new path if it isn't, but I'm not sure on how to get the position of the final point. (I'm not very experienced when it comes to tables)
wait() local statsscript = require(script.Parent.Stats) local enemies = script.Parent.EnemyFolder.Value function findNearestTorso(pos) local list = enemies:GetChildren() local torso = nil local dist = 500 local temp = nil local human = nil local temp2 = nil for x = 1, #list do temp2 = list[x] if (temp2.className == "Model") and (temp2 ~= script.Parent) then temp = temp2:findFirstChild("HumanoidRootPart") human = temp2:findFirstChild("Humanoid") if (temp ~= nil) and (human ~= nil) and (human.Health > 0) then if (temp.Position - pos).magnitude < dist then torso = temp dist = (temp.Position - pos).magnitude end end end end return torso end while true do wait() local target = findNearestTorso(script.Parent.HumanoidRootPart.Position) if target then local path = game:GetService("PathfindingService"):ComputeSmoothPathAsync(script.Parent.HumanoidRootPart.Position, target.Position, 500) local points = path:GetPointCoordinates() for _, point in ipairs(points) do script.Parent.Humanoid:MoveTo(point) repeat distance = (point - script.Parent.HumanoidRootPart.Position).magnitude wait() until distance < 3 end end end
You should NOT be looping through the table got from :GetPointCoordinates(). Instead, do this:
while wait() do local target = findNearestTorso(script.Parent.HumanoidRootPart.Position) if target then local path = game:GetService("PathfindingService"):ComputeSmoothPathAsync(script.Parent.HumanoidRootPart.Position, target.Position, 500) local points = path:GetPointCoordinates() if #points > 1 then script.Parent.Humanoid:MoveTo(points[2]) end end end
this way, your zombie can get to the player, even if the player moves. The reason that we dont move to the first vector3 value in the table is that it is where the NPC is (correct me if im wrong). Sometimes the second value also doesn't work so you can try the third one, as shown in this example code (not the best):
if #points > 2 then humanoid:MoveTo(points[3]) elseif #points > 1 then humanoid:MoveTo(points[2]) end