Alot of pathfinding zombies lags the game

local myHuman = script.Parent:WaitForChild(“Humanoid”)
local myRoot = script.Parent:WaitForChild(“HumanoidRootPart”)
myRoot:SetNetworkOwner(nil)
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
			
			myHuman.Jump = true
			walkRandomly()
		end
	end
else
	
	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
			
			findPath(target)
			break
		end
		if checkSight(target) then
			repeat
				
				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
			
			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

		return true
	end
end
return false

end

function findTarget()
local dist = 75
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 = 2000
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

this is a pathfinding zombie script and when i put alot of zombies in workspace, the ping starts to go up to 200s when its normally 80 to 90

how can i prevent lag when there is alot of zombies?

1 Like

Uhh did you even look at your own post? Please format your code like this

function example()
print(“hello”)
end

Not like this

function example()

print(“helloe”)

end

not my issue that it has a text limit so it wont work

Can you find a workaround for that? I can read the code like this but they way it currently is will demotivate people into helping you

Anyways parallel lua can be really helpfull here:

It is pretty hard to understand at first but it is worth it
And you could look into this beta feature (since its beta it wont work in the published game and only in studio soo…)

1 Like

You might be able to use the profiler to help optimize this script. The most likely reason that it’s laggy is because Roblox pathfinding is slow and you are computing the path too often.

You’ll need to use a custom replication system for something that uses this many humanoids. I was able to do this with a somewhat hacky solution here:

Basically:

  • Put the actual Zombie NPC in the server Camera to completely stop replication but keep physics simulation
  • Make a “replicator” part (I clone the Zombie’s root part) that’s not collidable in any way, and weld this to the Zombie, keep this in the workspace with the Server as the network owner
  • Have clients render the zombies locally, use remote events to tell everyone what the zombie’s supposed to be doing (in my case it was just animations/sounds)

Though in my opinion the best solution out there would just be Chickynoid but I don’t have the time to learn all that.

1 Like

From the looks of the script, it looks like the script is in each and every zombie, which could cause more lag.

There are a lot of things you can do to optimize an NPC. For example, if you have line of sight to the target and there is a valid path to the target then simply walk directly to the target and avoid pathfinding (This can be hit or miss depending on map geometry but it is good for flatish terrain). Also if you have a target and are navigating towards the target, dont update the pathfinding if the target hasnt moved just use the same path until the target has moved a few studs away from its previous position. Its important to only update the pathfinding when you need to. It is also important to differentiate between what should and shouldnt be running serverside. For example all your audio and animation related things could very easily be ran clientside. Also the section where you check if the lowertorso is being touched, you could remove that section and then within your pathfinding check for Waypoint.Action and if Waypoint.Action == Enum.PathWaypointAction.Jump then you can just the humanoid. Another thing you could do is instead of constantly looking for new targets, if you already have a target then make that zombie just focus on that target for a little bit. You could add a cooldown to when they lose interest or something.

it comes down to how you manage zombies in code. I cannot pinpoint your issue.

lets take for example, path:computeasync, if you call this too many times so constantly with many npcs it will cause lag.

you will need to determine when it is applicable to call compute async once for a long time (or alternatively just call moveto and do pauses) until

in close enough range of an enemy player to start accurately pathfinding to (or allowing those ahead of the npc priority for more constant assessments for accurate pathfinding