AI script causing performances issues

The AI script I have causes lag after awhile. I only let 30 NPC’s spawn anymore then that would cause more lag. When lag starts to build up the swords I have in the game don’t work properly, also when you die it will take forever to load back into the menu. Not sure what’s causing it but if anyone can help would be appreciated. Thanks.

AI Script:

function ManageAI(AI)
spawn(function()
if AI then
local function GetTool(AI)
local Tool = nil
for i,v in pairs(AI:GetChildren()) do
if v:IsA("Tool") then
Tool = v
end
end
return Tool
end

local Cooldown = 0
local BaseDamage = 0
local Variation = math.random(0,0)

local Tool = GetTool(AI)
local Sword = Tool:WaitForChild("Handle")
local attacking = false
local Torso = AI:WaitForChild("Torso")
local AIHuman = AI:WaitForChild("Humanoid")
local Destination = nil

local Startpoint = Instance.new("Part")
Startpoint.Transparency = 1
Startpoint.CanCollide = false
Startpoint.CFrame = Torso.CFrame

local function RandomMovement()
if Destination then
if (Torso.Position - Destination).magnitude > 3 then
AIHuman:MoveTo(Destination)
if AIHuman.Parent then
AIHuman.WalkSpeed = AIHuman.Parent.SpeedValue.Value * 1
end
else Destination = nil
end
else
local turn = (math.random(0,72) * 5)
local goal = Instance.new("Part")
goal.Transparency = 0
goal.CanCollide = false
goal.Anchored = true
goal.Parent = AI
goal.CFrame = Startpoint.CFrame * CFrame.Angles(0,turn,0)
goal.CFrame = goal.CFrame + goal.CFrame.lookVector * 10
goal.Position = goal.Position + Vector3.new(math.random(-0.1,0.1),math.random(-0.1,0.1),math.random(-0.1,0.1))
Destination = Vector3.new(goal.Position.X,goal.Position.Y,goal.Position.Z)
goal:Destroy()
wait(2)
end
wait(.2)
end

local function FindNearbyEnemies()
local NearbyEnemy = nil
local ClosestDist = 30
local EnemyHumanoid = nil
for i,v in pairs(game.Workspace:GetChildren()) do
if v:IsA("Model") then
for a,b in pairs(v:GetChildren()) do
if v:FindFirstChild("Humanoid") and v:FindFirstChild("HumanoidRootPart") then
if v:FindFirstChild("Humanoid").Health > 0 and v.Name ~= "ExpremeMist" and not v:FindFirstChild("ForceField") and not v:FindFirstChild("AI") and not v:FindFirstChild("BOSS") then
local EnemTorso = v:FindFirstChild("HumanoidRootPart")
if EnemTorso.Position.Y + 5 >= Torso.Position.Y and (Torso.Position - EnemTorso.Position).magnitude < ClosestDist then
ClosestDist = (Torso.Position - EnemTorso.Position).magnitude
NearbyEnemy = v:FindFirstChild("HumanoidRootPart")
EnemyHumanoid = v:FindFirstChild("Humanoid")
end
end
end
end
end
end
return {ClosestDist,NearbyEnemy,EnemyHumanoid}
end

Sword.Touched:connect(function(hit)
if (hit.Parent == nil) then return end
local Hitchar = hit.Parent
local HitcharN = Hitchar.Name
local Humanoid = hit.Parent:FindFirstChild("Humanoid")
local AtkDMG = BaseDamage + Variation
if HitcharN ~= AI.Name and attacking == true then
if Humanoid and Humanoid.Health > 0 and not Hitchar:FindFirstChild("BOSS") and not Hitchar:FindFirstChild("AI") and Hitchar.Name ~= "therealkhjking2" then
Humanoid.Health = Humanoid.Health - AtkDMG
attacking = false
end
end
end)

local function attack(Target)
	if Cooldown == 0 then
	Cooldown = 0.6
	spawn(function()
	AIHuman.AutoRotate = true
	AIHuman:MoveTo(Target.Position)
	wait()
	attacking = true
	AIHuman.WalkSpeed = AIHuman.Parent.SpeedValue.Value == 2
	Tool:Activate()
	local jumpTime = math.random(1,5)
	if jumpTime == 1 then
	AIHuman.Jump = true
	end
	wait(0.33)
	if jumpTime > 1 then
	AIHuman.Jump = true
	end
	wait(0.27)
	attacking = false
	Cooldown = 0
	end)
	end
end

local function approach(Target)
AIHuman.AutoRotate = true
if AIHuman.Parent then
AIHuman.WalkSpeed = AIHuman.Parent.SpeedValue.Value * 1
end
AIHuman:MoveTo(Target.Position)
wait(.1)
end

local function Flee(Enemy)
AIHuman.AutoRotate = true
AIHuman:MoveTo(Enemy.Position)
if AIHuman.Parent then
AIHuman.WalkSpeed = AIHuman.Parent.SpeedValue.Value * .65
end
wait()
AIHuman.AutoRotate = false
AIHuman:Move(Torso.CFrame.lookVector * -20,false)
wait(0.05)
end

while wait(0.1) do
if AI and AIHuman and AIHuman.Health > 0 then
local TargetInfo = FindNearbyEnemies()
local Target = TargetInfo[2];
local TargetDist = TargetInfo[1];
local TargetHumanoid = TargetInfo[3];
if math.random(1,70) == 30 then
AIHuman.Jump = true
end
if Target then
if TargetDist < 10 then
attack(Target)
end
if AIHuman.Health < AIHuman.MaxHealth * 0.5 and TargetDist < 60 then
Flee(Target)
elseif TargetDist > 30 then
approach(Target)
elseif Cooldown == 0 and TargetDist >= 10 then
approach(Target)
else Flee(Target)
end
else RandomMovement()
end
elseif not AI or AI == nil then AI = nil break end
end
if not AI or AI == nil then
return nil
end
end
end)
end

for i,v in pairs(game.Workspace:GetChildren()) do
if v:FindFirstChild("AI") then
ManageAI(v)
end
end

game.Workspace.ChildAdded:connect(function(c)
if c:FindFirstChild("AI") then
ManageAI(c)	
end
end) 
3 Likes

The FindNearbyEnemies() function in your script loops through every single children in the workspace. That’s probably going to do a bunch of unnecessary loops.

I’d recommend using the CollectionService to tag every Humanoid instance when they spawn and loop through the list with CollectionService:GetTagged(). The humanoid also contains the RootPart property for you to use to check the distance so you don’t have to use FindFirstChild() so much.

I hope this helps, good luck.

3 Likes

Rather than that, couldn’t he just loop through all the players currently in the game using game:GetService(“Players”):GetPlayers()?

I’ve never used collection service so I’m not sure how efficient it is, but seems like a good alternative.

1 Like

You should disable unnecessary humanoid states if you haven’t already to decrease performance problems.

If he is only planning for the AI to target players only then yeah, otherwise this method allows his AIs target other AIs.