Collection Service only affecting one instance

So I have a AI script that works fine, but it lags when there are a lot of them, I tried to implement Collection service, but it doesn’t seem to affect more than one of the AI’s.

Here is the code on a script in ServerscriptService

local CollectionService = game:GetService("CollectionService")

wait(5)

function walkRandomly(myRoot, myHuman, walkanim, IdleAnim)
	local xRand = math.random(-10,10)
	local zRand = math.random(-10,10)
	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
		--walkanim:Play()
		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(myRoot, myHuman, walkanim, IdleAnim)
			end
			if timeOut then
				local lastwaypoint = table.find(waypoints,waypoint)
				if lastwaypoint == #waypoints then
					--walkanim:Stop()
					--IdleAnim:Play()
				end
			end
		end
	else
		wait(1)
		walkRandomly(myRoot, myHuman, walkanim, IdleAnim)
	end
end

function findPath(target, myRoot, myHuman, walkanim, IdleAnim, damage, db, attackanim)
	local path = game:GetService("PathfindingService"):CreatePath()
	path:ComputeAsync(myRoot.Position,target.Position)
	local waypoints = path:GetWaypoints()
	
	if path.Status == Enum.PathStatus.Success then
		if db == true then
			myHuman.WalkSpeed = 18
		end
		for _, waypoint in ipairs(waypoints) do
			--walkanim:Play()
			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, myRoot, myHuman, walkanim, IdleAnim, damage, db, attackanim)
				--walkanim:Stop()
				--IdleAnim:Play()
				break
			end
			if timeOut then
				local lastwaypoint = table.find(waypoints,waypoint)
				if lastwaypoint == #waypoints then
					--walkanim:Stop()
					--IdleAnim:Play()
				end
			end
			repeat
				myHuman:MoveTo(target.Position)
				attack(target, myRoot, damage, db, attackanim)
				wait(0.1)
				if target == nil then
					--walkanim:Stop()
					--IdleAnim:Play()
					break
				elseif target.Parent == nil then
					--walkanim:Stop()
					--IdleAnim:Play()
					break
				end
			until myHuman.Health < 1 or target.Parent.Humanoid.Health < 1
			if (myRoot.Position - waypoints[1].Position).magnitude > 20 then
				findPath(target)
				--walkanim:Stop()
				--IdleAnim:Play()
				break
			end
		end
	else
		walkRandomly(myRoot, myHuman, walkanim, IdleAnim)
	end
end

function findTarget(myRoot)
	local dist = 400
	local target = nil
	local potentialTargets = {}
	for i,v in ipairs(game.Players:GetChildren()) do
		local human = v.Character:FindFirstChild("Humanoid")
		local torso = v.Character:FindFirstChild("HumanoidRootPart")
		if human and torso and v.Name ~= myRoot.Parent.Name then
			if (myRoot.Position - torso.Position).magnitude < dist and human.Health > 0 then
				table.insert(potentialTargets,torso)
			end
		end
	end
	for i,v in ipairs(potentialTargets) do
		if (myRoot.Position - v.Position).magnitude < dist then
			target = v
			dist = (myRoot.Position - v.Position).magnitude
		end
	end
	return target
end

function attack(target, myRoot, damage, db, attackanim)
	if (myRoot.Position - target.Position).magnitude < 6 then
		if target.Parent ~= nil and db == true then
			db = false
			attackanim:Play()
			local oldspeed = myRoot.Parent.Zombie.WalkSpeed
			myRoot.Parent.Zombie.WalkSpeed = 0
			wait(0.2)
			target.parent.Humanoid:TakeDamage(damage)
			wait(1.75)
			db = true
			myRoot.Parent.Zombie.WalkSpeed = oldspeed
		end
		wait(0.4)
	end
end

function main(Zombie)
	local myHuman = Zombie:WaitForChild("Zombie")
	local myRoot = Zombie:WaitForChild("HumanoidRootPart")
	local head = Zombie:WaitForChild("Head")
	local lowerTorso = Zombie:WaitForChild("LowerTorso")
	local damage = Zombie:WaitForChild("Damage").Value
	local db = true
	
	local walkanim = Zombie.Zombie:LoadAnimation(Zombie.Walk)
	local IdleAnim = Zombie.Zombie:LoadAnimation(Zombie.Idle)
	local attackanim = Zombie.Zombie:LoadAnimation(Zombie.Attack)
	local target = findTarget(myRoot)
	if target then
		findPath(target, myRoot, myHuman, walkanim, IdleAnim, damage, db, attackanim)
	else
		wait(math.random(1,4))
		walkRandomly(myRoot, myHuman, walkanim, IdleAnim)
	end
end


game:GetService("RunService").Heartbeat:Connect(function()
	for _,Zombie in pairs(CollectionService:GetTagged("Zombie")) do
		main(Zombie)
	end
end)

I’ve searched around and found that global values break the script, so i’ve combed through the script about 4 times, but haven’t found any global values

It probably means you tagged only one zombie

1 Like

I tagged all of them using a plugin https://www.roblox.com/library/948084095/Tag-Editor

Each time you run the function once, the next function has to wait for that function to stop waiting, I suggest using:

spawn(function()
   wait(1)
end)

This won’t let the other lines of code outside the function wait for it to finish, this is the same for running functions.

What I suggest changing a part of the code to:

game:GetService("RunService").Heartbeat:Connect(function()
	for _,Zombie in pairs(CollectionService:GetTagged("Zombie")) do
		spawn(function()
			main(Zombie)
		end)
	end
end)

So what I should be:

local CollectionService = game:GetService("CollectionService")

wait(5)

function walkRandomly(myRoot, myHuman, walkanim, IdleAnim)
	local xRand = math.random(-10,10)
	local zRand = math.random(-10,10)
	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
		--walkanim:Play()
		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(myRoot, myHuman, walkanim, IdleAnim)
			end
			if timeOut then
				local lastwaypoint = table.find(waypoints,waypoint)
				if lastwaypoint == #waypoints then
					--walkanim:Stop()
					--IdleAnim:Play()
				end
			end
		end
	else
		wait(1)
		walkRandomly(myRoot, myHuman, walkanim, IdleAnim)
	end
end

function findPath(target, myRoot, myHuman, walkanim, IdleAnim, damage, db, attackanim)
	local path = game:GetService("PathfindingService"):CreatePath()
	path:ComputeAsync(myRoot.Position,target.Position)
	local waypoints = path:GetWaypoints()
	
	if path.Status == Enum.PathStatus.Success then
		if db == true then
			myHuman.WalkSpeed = 18
		end
		for _, waypoint in ipairs(waypoints) do
			--walkanim:Play()
			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, myRoot, myHuman, walkanim, IdleAnim, damage, db, attackanim)
				--walkanim:Stop()
				--IdleAnim:Play()
				break
			end
			if timeOut then
				local lastwaypoint = table.find(waypoints,waypoint)
				if lastwaypoint == #waypoints then
					--walkanim:Stop()
					--IdleAnim:Play()
				end
			end
			repeat
				myHuman:MoveTo(target.Position)
				attack(target, myRoot, damage, db, attackanim)
				wait(0.1)
				if target == nil then
					--walkanim:Stop()
					--IdleAnim:Play()
					break
				elseif target.Parent == nil then
					--walkanim:Stop()
					--IdleAnim:Play()
					break
				end
			until myHuman.Health < 1 or target.Parent.Humanoid.Health < 1
			if (myRoot.Position - waypoints[1].Position).magnitude > 20 then
				findPath(target)
				--walkanim:Stop()
				--IdleAnim:Play()
				break
			end
		end
	else
		walkRandomly(myRoot, myHuman, walkanim, IdleAnim)
	end
end

function findTarget(myRoot)
	local dist = 400
	local target = nil
	local potentialTargets = {}
	for i,v in ipairs(game.Players:GetChildren()) do
		local human = v.Character:FindFirstChild("Humanoid")
		local torso = v.Character:FindFirstChild("HumanoidRootPart")
		if human and torso and v.Name ~= myRoot.Parent.Name then
			if (myRoot.Position - torso.Position).magnitude < dist and human.Health > 0 then
				table.insert(potentialTargets,torso)
			end
		end
	end
	for i,v in ipairs(potentialTargets) do
		if (myRoot.Position - v.Position).magnitude < dist then
			target = v
			dist = (myRoot.Position - v.Position).magnitude
		end
	end
	return target
end

function attack(target, myRoot, damage, db, attackanim)
	if (myRoot.Position - target.Position).magnitude < 6 then
		if target.Parent ~= nil and db == true then
			db = false
			attackanim:Play()
			local oldspeed = myRoot.Parent.Zombie.WalkSpeed
			myRoot.Parent.Zombie.WalkSpeed = 0
			wait(0.2)
			target.parent.Humanoid:TakeDamage(damage)
			wait(1.75)
			db = true
			myRoot.Parent.Zombie.WalkSpeed = oldspeed
		end
		wait(0.4)
	end
end

function main(Zombie)
	local myHuman = Zombie:WaitForChild("Zombie")
	local myRoot = Zombie:WaitForChild("HumanoidRootPart")
	local head = Zombie:WaitForChild("Head")
	local lowerTorso = Zombie:WaitForChild("LowerTorso")
	local damage = Zombie:WaitForChild("Damage").Value
	local db = true
	
	local walkanim = Zombie.Zombie:LoadAnimation(Zombie.Walk)
	local IdleAnim = Zombie.Zombie:LoadAnimation(Zombie.Idle)
	local attackanim = Zombie.Zombie:LoadAnimation(Zombie.Attack)
	local target = findTarget(myRoot)
	if target then
		findPath(target, myRoot, myHuman, walkanim, IdleAnim, damage, db, attackanim)
	else
		wait(math.random(1,4))
		walkRandomly(myRoot, myHuman, walkanim, IdleAnim)
	end
end


game:GetService("RunService").Heartbeat:Connect(function()
	for _,Zombie in pairs(CollectionService:GetTagged("Zombie")) do
		spawn(function()
			main(Zombie)
		end)
	end
end)

Thanks a lot, that seemed to have worked

I have one question left though. I tried the collection service with many instances and it was very laggy as the frames dropped lower. I then tried it without collection service and it was les laggy than with collection service and I’d like to know why and possibly how to fix this.

This is the NPCs but only a few and broken down into r6 characters This is the NPCs with around 128 of them also cut down into R6

I’ve already turned off as many Humanoid States as possible