The reason why your game is lagging is because your entire code is a loop that loops other loops that create connections with loops.
I’d highly, HIGHLY, recommend reconsidering your code.
Small things would just be to use task.wait rather than wait, but thats not going to fix the major problems:
Creation (anything instance.new related):
You’re creating parts of the hitbox on demand, then destroying them right after, over and over. Consider utilizing object pooling rather than creating, connecting, destroying. This also goes for other instances that you may need to create again, considering finding ways to re-utilize the instance instead of creating a new one every time.
Connections inside loops inside connections:
while true do
if character.Humanoid.Health < 1 then
return
end
i += 1
wait(1)
if ability1 then
if i % cooldown1.Value == 0 then
local connection = npcmodule[ability1.Value](character)
character.Humanoid.Died:Connect(function()
if connection then
connection:Disconnect()
end
return
end)
end
end
end
This is a red flag, you have a connection loop inside a while true do loop that is constantly checking the health AND creating a connection that checks when the player dies.
function npcmodule.Run(character)
if not character.PrimaryPart then
return
end
local closestPlayer = ClosestPlayer(character.PrimaryPart.Position)
local createdNPC = workspace.CreatedNPCFolder
local closestNpc = nil
local random = math.random(1, #createdNPC:GetChildren())
for i,child in ipairs(createdNPC:GetChildren()) do
if i == random then
closestNpc = child
end
end
if character.Humanoid.Health == 1 then
if not closestNpc.PrimaryPart then
return
end
character.Humanoid:MoveTo(closestNpc.PrimaryPart.Position)
character.Humanoid.MoveToFinished:Wait()
else
return
end
end
For loops can be laggy (depending on context)
You are calling this function somewhere (idk where, Im not looking to closely) and considering the name of the function, im assuming you’re calling this on 10+ npcs as you mentioned.
function npcmodule.Ask(character)
if not character.PrimaryPart then
return
end
local ask = modelFolder:FindFirstChild("None000Ask"):Clone()
local id = 77050504380973
local still = false
ask.Parent = workspace
ask.Position = character.PrimaryPart.Position + Vector3.new(0,7,0)
game.Debris:AddItem(ask,4)
character.PrimaryPart.Anchored = true
local animation = PlayAnimation(character, id)
character.PrimaryPart.Orientation = Vector3.new(character.PrimaryPart.Orientation.X,character.PrimaryPart.Orientation.Y,0)
still = true
character.Humanoid:GetPropertyChangedSignal("Health"):Connect(function()
if still == true and character.Humanoid.Health > 0 then
ask:Destroy()
still = false
animation:Stop()
animation:Destroy()
local rageAnim = PlayAnimation(character, 77924139036595)
ask:Destroy()
character.PrimaryPart.Anchored = true
character.PrimaryPart:FindFirstChild("Angry"):Play()
character.Humanoid.WalkSpeed += 8
character["Body Colors"].HeadColor = BrickColor.new("Really red")
character["Body Colors"].RightLegColor = BrickColor.new("Really red")
character["Body Colors"].LeftLegColor = BrickColor.new("Really red")
character["Body Colors"].LeftArmColor = BrickColor.new("Really red")
character["Body Colors"].RightArmColor = BrickColor.new("Really red")
local fire = Instance.new("Fire")
fire.Parent = character.Head
rageAnim.Ended:Wait()
rageAnim:Destroy()
local explosion = Instance.new("Explosion")
explosion.Parent = character.PrimaryPart
explosion.Position = character.PrimaryPart.Position
explosion.BlastPressure = 0
explosion.BlastRadius = 0
character.PrimaryPart.Explode:Play()
character.Humanoid.Health += 30
game.Debris:AddItem(explosion, 3)
character.PrimaryPart.Anchored = false
return
end
end)
wait(3)
animation:Stop()
animation:Destroy()
if still == true then
local healclone = modelFolder.Heal:Clone()
healclone.Parent = character.PrimaryPart
healclone:Emit(30)
character.PrimaryPart.Heal:Play()
character.Humanoid.Health += 20
game.Debris:AddItem(healclone,4)
end
still = false
wait(0)
ask:Destroy()
character.PrimaryPart.Anchored = false
end
For this function, you’re checking every time if the health changes to 0, couldnt you just check if the humanoid dies?
function npcmodule.npcMain(character)
local hitbox = Instance.new("Part")
local hitboxTouched = false
hitbox.Size = Vector3.new(3.5*character:GetScale(),4*character:GetScale(),3.5*character:GetScale())
hitbox.Anchored = true
hitbox.CanCollide = false
hitbox.Transparency = 1
hitbox.Material = Enum.Material.ForceField
hitbox.Parent = workspace
hitbox.Color = Color3.new(1, 0, 0)
local npcabilityConnection = coroutine.create(npcAbilityHandler)
while true do
game["Run Service"].Heartbeat:Wait()
if character and character:FindFirstChild("HumanoidRootPart") and character.PrimaryPart and character.Humanoid.Health > 0 then
if character.Humanoid.Health < 1 then
hitbox:Destroy()
npcabilityConnection:Disconnect()
return
end
local configuration = character:FindFirstChild("Configuration")
hitbox.Position = character.PrimaryPart.Position
local target = ClosestPlayer(character.PrimaryPart.Position)
if target then
character.Humanoid:MoveTo(target.PrimaryPart.Position)
for i,z in ipairs(character:GetChildren()) do
if z:IsA("BasePart") then
z:SetNetworkOwner(game.Players:GetPlayerFromCharacter(target))
end
end
hitbox.Touched:Connect(function(hit)
if hit.Parent == target and HitboxCooldown == false and hit.Parent.Parent ~= workspace.CreatedNPCFolder then
HitboxCooldown = true
hit.Parent.Humanoid.Health -= configuration.Damage.Value
wait(configuration.DamageCooldown.Value)
HitboxCooldown = false
end
end)
end
else
hitbox:Destroy()
coroutine.yield(npcAbilityHandler)
return
end
end
end
This is by far the worst offender:
the while true do loop does all the following:
does a wait
checks humanoid/character
checks health
FindFirwstChild config
changes hitbox pos
checks target
if has target, do the following, create connection and for loop
set network owner
And all of this code is being done on presumably 10-40 npcs?