My script is absolutely annihilating my frames

I have a incomplete zombie pathfinding script and when I leave it running for a certain amount of time , my frames gradually become worse. Here is the script :
local isMoving = false
local humanoid = script.Parent.Humanoid
local model = script.Parent
local PFS = game:GetService(“PathfindingService”)
local agroDistance = 150
local blackListedParts = {}

humanoid.MoveToFinished:Connect(function()
isMoving = false
end)

while true do
wait()
local entireWorkSpace = game.Workspace:GetChildren()
local possibleTargets = {}

for i,v in pairs(entireWorkSpace) do
	if v:FindFirstChild("Humanoid") and v.Parent ~= script.Parent then
		possibleTargets[i] = v:FindFirstChild("UpperTorso")
		
	end
end

local closestTarget = game.Workspace.referencePart

for i,v in pairs(possibleTargets) do
	if (closestTarget.Position - model.UpperTorso.Position).Magnitude > (v.Position - model.UpperTorso.Position).Magnitude then
		if v.Parent ~= model then
			closestTarget = v
		end
	end
end

if closestTarget then
	print("is Human")
	if (closestTarget.Position - model.HumanoidRootPart.Position).Magnitude <= agroDistance then
		local params =  RaycastParams.new()
		local maginitude = (closestTarget.Position - model.HumanoidRootPart.Position).Magnitude
		
		
		for i,v in pairs(entireWorkSpace) do
			if v:FindFirstChild("Humanoid") then
				for a,b in pairs(v:GetChildren()) do
					if b:IsA("MeshPart") or b:IsA("Accessory") or b:IsA("Part") then
						table.insert(blackListedParts,b)
					end
				end
			end
		end
		
		params.FilterDescendantsInstances = blackListedParts
		params.FilterType = Enum.RaycastFilterType.Blacklist
		local rayCastResults = game.Workspace:Raycast(model.UpperTorso.Position,(closestTarget.Position-model.UpperTorso.Position).Unit*(maginitude-1),params)
		if rayCastResults  then
			humanoid:MoveTo(model.UpperTorso.Position)
			local path = PFS:CreatePath()
			path:ComputeAsync(model.UpperTorso.Position,closestTarget.Position)
		else
			humanoid:MoveTo(closestTarget.Position)
			table.clear(blackListedParts)
		end
	else
		if isMoving == false then
			humanoid:MoveTo(model.UpperTorso.Position + Vector3.new(math.random(-30,30),model.UpperTorso.Position.Y,math.random(-30,30)))
			isMoving = true
			table.clear(blackListedParts)
		end
	end
end

end

1 Like

I can see one problem. Most scripters advise against using wait(). You may want to use RunService.Heartbeat:wait() instead, or a similar function of RunService.

In addition, you may want to consider changing how the script looks for targets. If it is only looking for players, you can just iterate through everyone in game.Players, checking if their characters exist and accessing them that way (each player has a Character property that points to their corresponding character model in the Workspace). Doing this would drastically reduce the runtime of the for loop.

If the zombie is looking for non-player targets as well, you may want to consider grouping all NPC’s in a single model (or Folder) and looking through all children of both that and Players, unless you need NPC’s to be grouped within other models. I have yet to do this myself, but I have plans to do something similar and figured sharing the idea may help.

1 Like

You should really put the players that join and/or NPCs in a table so that way the loops don’t have to check every single part that there’s in the workspace.

Also like said above, you might want to use RunService.Heartbeat:Wait() instead of a while loop.

Ok thanks let me try that right now.

I have made it so that the code runs off heartbeat and I have made a module script that has all the players and NPC character models and I am looping through that instead but now the lag has gotten even worse. My entire studio almost crashed.

Edit : the almost crashing part only happens once a player/NPC is in the zombies agro distance.

I meant making a table on the zombie script or just grouping the NPCs in a folder so the for loop takes less to check through all parts.

For players you can check it pretty easily with the .Character property of players in game.Players.

It still does not explain the lag , because it is not the part where it loops through the player models but when they player is in range of the zombie , here :
if rayCastResults then
humanoid:MoveTo(model.UpperTorso.Position)
local path = PFS:CreatePath()
path:ComputeAsync(model.UpperTorso.Position,closestTarget.Position)
else
humanoid:MoveTo(closestTarget.Position)
table.clear(blackListedParts)
end
else
if isMoving == false then
humanoid:MoveTo(model.UpperTorso.Position + Vector3.new(math.random(-30,30),model.UpperTorso.Position.Y,math.random(-30,30)))
isMoving = true
table.clear(blackListedParts)
end
end

Cant you put players in that folder too?

Can you try removing this part of your code (line 2-3 in the snippet)? You’re not using it at all. You could also clear blackListedParts in this branch too.

Try using the isMoving variable to implement a debounce in that script since it seems like once the player is in range it keeps firing every single frame. Or just a debounce in general.

Although this may cause the zombie to not change directions at all until it reaches the end of the computed path.

I did try that , didn’t change anything.

Ye that is the issue why I can’t do that.

when you used while true do you used wait() instead add task.wait() that might fix your fps problem

what is task.wait() . never seen it before

fam i feel you. its like a “better” wait function. here is a link to the task library.
task (roblox.com)

sorry i took so long ive been busy all day but task.wait() is just a better wait() and fixes loop lag/fps drops (i always forgot what it means and what its for)

Heartbeat was a bad idea because it was able to fire even before the loop could finish because there were sections of the loop that waited until the NPC/ Player had completed their movement , therefor there were way too many firing at once.

True, one could script the player characters to be put in that folder when spawning, as long as one doesn’t need them parented to anything else.