Pathfinding AI script ruins game performance

I’ve reccently been trying to make a pathfinding ai enemy and i made a script that does everything i need! but the problem is after playing for a while the performance seems to descrease and i got 3 fps at one point, heres my code

local NPC = script.Parent
local pathfinding_service = game:GetService("PathfindingService")

function getClosestPlayer()
	local closest_player, closest_distance = nil, math.huge
	for i, player in pairs(workspace:GetChildren()) do
		if player:FindFirstChild("Humanoid") and player ~= NPC then
			local distance = (NPC.PrimaryPart.Position - player.PrimaryPart.Position).Magnitude
			if distance < closest_distance then
				closest_player = player
				closest_distance = distance
			end
		end
	end
	return closest_player, closest_distance
end

while wait() do
	local path = pathfinding_service:CreatePath()
	local player, distance = getClosestPlayer()
	if player and player.Humanoid.Health > 0 and distance > 10 then
		if distance > 70 and player.HumanoidRootPart.Position.Y > NPC.HumanoidRootPart.Position.Y + 5 then
-- this is just used for jumping 
			NPC.Humanoid.Jump = true
			wait(.1)
			NPC.Humanoid.Jump = false
			NPC.HumanoidRootPart.CFrame = CFrame.new(NPC.HumanoidRootPart.Position,player.HumanoidRootPart.Position)
			local bodymover = Instance.new("BodyVelocity")
			bodymover.Parent = NPC.HumanoidRootPart
			bodymover.Velocity = NPC.HumanoidRootPart.CFrame.LookVector * 500
			game:GetService("Debris"):AddItem(bodymover,.4)
		end
		print(distance)
		path:ComputeAsync(NPC.HumanoidRootPart.Position, player.PrimaryPart.Position)
		local waypoints = path:GetWaypoints()
		for _, waypoint in pairs(waypoints) do  
			NPC.Humanoid:MoveTo(waypoint.Position)
		end
	elseif player and player.Humanoid.Health > 0 and not player:FindFirstChildWhichIsA("ForceField") and distance < 10 then
-- used for if player is too close to enemy, kill the player
		NPC.HumanoidRootPart.death:Play()
		local bodymover = Instance.new("BodyVelocity")
		bodymover.Parent = player.HumanoidRootPart
		bodymover.Velocity = -player.HumanoidRootPart.CFrame.LookVector * 800 + player.HumanoidRootPart.CFrame.UpVector * 500
		game:GetService("Debris"):AddItem(bodymover,.15)
		player.Humanoid:TakeDamage(999)
	end
end

im not exactly sure what i should do to try and make it run better since i have to keep updating the target since the player is moving around. Can anyone help?

You don’t really need to calculate a path every 0.03 seconds do you?

no but wouldn’t increasing the delay make the ai not go to the right place cause the player can move. I’m sort of new to the pathfinding system so correct me if I’m wrong

You only really need to check an enemy’s position every second or two at most - the actual movement can be handled a slightly faster runtime but honestly it makes no difference in practically.

What does make a difference is a heavy script on the server.

The most annoying thing I find with AI enemies (not just on Roblox) is when they seem to be daudling or slowly moving from one place to another. Sure, this could be caused by a slow-updating tracker like I’m suggesting, but having slow updates due to bad performance is even worse as you not only cripple the AI, but possibly the player’s experience as well as any tools both the user or AI use.

Increase your wait time to 2 seconds and handle moving the AI on a separate loop at a slightly faster speed.

One good thing to note is that Humanoid:MoveTo is kind of like a Tween - you don’t consistently need to update it because Roblox is handling the movement to (waypoint.Position) for you - you just need to handle turning corners and stopping.

You could probably even make use of Roblox’s new Parallel Lua feature - compute and put all your waypoints into a list every second or so asynchronously - then - synchronise and Move the humanoids as required, which will probably give you more resources to handle more complex AI should you choose develop such.

Parallel Lua Beta - Updates / Announcements - DevForum | Roblox