I want the zombie to chase the closest player using pathfinding
The issue is, the zombie does not move at all, and path status will always showEnum.PathStatus.NoPathfor some reason
I haven’t try any solution so far, but changing local target = FindNearestPlayer()to local target = workspace.Pathwhich is a part that makes the script work normally.
I am aware that the problem is thelocal function FindNearestPlayer()functionbut I don’t know how to fix it.
Here is the script:
local zombie = script.Parent
local human = zombie.Humanoid
local root = zombie.HumanoidRootPart
local dmgDebounce = false
local pathfinding = game:GetService("PathfindingService")
local players = game:GetService("Players")
local detectRange = 200
local path = pathfinding:CreatePath()
function FindNearestPlayer()
print("searching")
for i, plr in pairs(players:GetPlayers()) do
print(plr.Name)
if plr.Character ~= nil and plr.Character:FindFirstChild("HumanoidRootPart") then
if (plr.Character.HumanoidRootPart.Position - root.Position).Magnitude <= detectRange then
return plr.Character.HumanoidRootPart
end
end
end
return nil
end
function chase(part)
path:ComputeAsync(root.Position, part.Position)
print(path.Status)
if path.Status == Enum.PathStatus.Success then
local waypoints = path:GetWaypoints()
for i, v in pairs (waypoints) do
human:MoveTo(v.Position)
print("chasing")
human.MoveToFinished:Wait()
if v.Action == Enum.PathWaypointAction.Jump then
human.Jump = true
end
if (waypoints[#waypoints].Position - part.Position).magnitude > 15 then
break
end
end
end
end
zombie.Torso.Touched:Connect(function(part)
local humanoid = part.Parent:FindFirstChild("Humanoid")
if part and part.Parent.Name ~= "Zombie" and human.Health > 0 and humanoid and not dmgDebounce then
dmgDebounce = true
zombie.Head.Attack:Play()
print("damaging")
humanoid:TakeDamage(math.random(10,20))
wait(5)
dmgDebounce = false
end
end)
while true do
local target = FindNearestPlayer()
if target ~= nil then
chase(target)
local p = Instance.new("SphereHandleAdornment")
p.Color3 = Color3.fromRGB(255,0,0)
p.Adornee = workspace.Terrain
p.CFrame = CFrame.new(target.Position)
p.AlwaysOnTop = true
p.Parent = workspace.Terrain
game.Debris:AddItem(p,1)
end
wait()
end
Does the script find and return a target Player? Try adding a print statement before the return plr.Character.HumanoidRootPart in the FindNearestPlayer function. If that works, then move to the next step and place print statements into the chase function at various points to confirm the NPC is doing it is expected to do.
Print is a great simple way to check that your script is doing what you expected, scatter it liberally throughout when testing.
You might want to check out this article on pathfinding in Roblox. It can help your script and also help with some of the things you didn’t consider, such as the path being blocked.
local myHuman = script.Parent:WaitForChild("Humanoid")
local myRoot = script.Parent:WaitForChild("HumanoidRootPart")
local head = script.Parent:WaitForChild("Head")
local lowerTorso = script.Parent:WaitForChild("LowerTorso")
local grab = script.Parent:WaitForChild("Grab")
local grabAnim = myHuman:LoadAnimation(grab)
grabAnim.Priority = Enum.AnimationPriority.Action
local grabSound = head:WaitForChild("Attack")
local screamSound = head:WaitForChild("Scream")
local clone = script.Parent:Clone()
function walkRandomly()
local xRand = math.random(-50,50)
local zRand = math.random(-50,50)
local goal = myRoot.Position + Vector3.new(xRand,0,zRand)
local path = game:GetService("PathfindingService"):CreatePath()
path:ComputeAsync(myRoot.Position, goal)
local waypoints = path:GetWaypoints()
if path.Status == Enum.PathStatus.Success then
for _, waypoint in ipairs(waypoints) do
if waypoint.Action == Enum.PathWaypointAction.Jump then
myHuman.Jump = true
end
myHuman:MoveTo(waypoint.Position)
local timeOut = myHuman.MoveToFinished:Wait(1)
if not timeOut then
print("Got stuck")
myHuman.Jump = true
walkRandomly()
end
end
else
print("Path failed")
wait(1)
walkRandomly()
end
end
function findPath(target)
local path = game:GetService("PathfindingService"):CreatePath()
path:ComputeAsync(myRoot.Position,target.Position)
local waypoints = path:GetWaypoints()
if path.Status == Enum.PathStatus.Success then
for _, waypoint in ipairs(waypoints) do
if waypoint.Action == Enum.PathWaypointAction.Jump then
myHuman.Jump = true
end
myHuman:MoveTo(waypoint.Position)
local timeOut = myHuman.MoveToFinished:Wait(1)
if not timeOut then
myHuman.Jump = true
print("Path too long!")
findPath(target)
break
end
if checkSight(target) then
repeat
print("Moving directly to the target")
myHuman:MoveTo(target.Position)
attack(target)
wait(0.1)
if target == nil then
break
elseif target.Parent == nil then
break
end
until checkSight(target) == false or myHuman.Health < 1 or target.Parent.Humanoid.Health < 1
break
end
if (myRoot.Position - waypoints[1].Position).magnitude > 20 then
print("Target has moved, generating new path")
findPath(target)
break
end
end
end
end
function checkSight(target)
local ray = Ray.new(myRoot.Position, (target.Position - myRoot.Position).Unit * 40)
local hit,position = workspace:FindPartOnRayWithIgnoreList(ray, {script.Parent})
if hit then
if hit:IsDescendantOf(target.Parent) and math.abs(hit.Position.Y - myRoot.Position.Y) < 3 then
print("I can see the target")
return true
end
end
return false
end
function findTarget()
local dist = 50
local target = nil
local potentialTargets = {}
local seeTargets = {}
for i,v in ipairs(workspace:GetChildren()) do
local human = v:FindFirstChild("Humanoid")
local torso = v:FindFirstChild("Torso") or v:FindFirstChild("HumanoidRootPart")
if human and torso and v.Name ~= script.Parent.Name then
if (myRoot.Position - torso.Position).magnitude < dist and human.Health > 0 then
table.insert(potentialTargets,torso)
end
end
end
if #potentialTargets > 0 then
for i,v in ipairs(potentialTargets) do
if checkSight(v) then
table.insert(seeTargets, v)
elseif #seeTargets == 0 and (myRoot.Position - v.Position).magnitude < dist then
target = v
dist = (myRoot.Position - v.Position).magnitude
end
end
end
if #seeTargets > 0 then
dist = 200
for i,v in ipairs(seeTargets) do
if (myRoot.Position - v.Position).magnitude < dist then
target = v
dist = (myRoot.Position - v.Position).magnitude
end
end
end
if target then
if math.random(20) == 1 then
screamSound:Play()
end
end
return target
end
function attack(target)
if (myRoot.Position - target.Position).magnitude < 5 then
grabAnim:Play()
grabSound:Play()
if target.Parent ~= nil then
target.Parent.Humanoid:TakeDamage(25)
end
wait(0.4)
end
end
function died()
wait(5)
clone.Parent = workspace
game:GetService("Debris"):AddItem(script.Parent,0.1)
end
myHuman.Died:Connect(died)
lowerTorso.Touched:Connect(function(obj)
if not obj.Parent:FindFirstChild("Humanoid") then
myHuman.Jump = true
end
end)
function main()
local target = findTarget()
if target then
myHuman.WalkSpeed = 16
findPath(target)
else
myHuman.WalkSpeed = 8
walkRandomly()
end
end
while wait(0.1) do
if myHuman.Health < 1 then
break
end
main()
end