Hey there! I have a game where waves of NPCs spawn and attack the NPCs on the opposite team, as well as any players on the opposite team. I run into issues when more waves spawn, the game starts to lag. The NPCs also start to stutter and do not move correctly. I’m also having issues with their animations. If you could help in any way, that would be amazing! Here is a clip of what I mean. Code can be found below, and I can give more visuals if you need.
https://gyazo.com/a3ef5805ce574892ae413e35a436c9c8
This is my full script for NPC management. Any advice would be amazing. Thanks for all your help!
wait(5)
-- CONSTANTS
local numNPCs = 70
local RANGE = 50
local DAMAGE = 5
-- SERVICES
local PathfindingService = game:GetService("PathfindingService")
-- Pathing
local pathParams = {
AgentHeight = 5,
AgentRadius = 5,
AgentCanJump = false,
}
-- Tables
local humans = {}
local orcs = {}
-- Variables
local orcs = game.ReplicatedStorage:WaitForChild("OrcsUnlocked")
local humans = game.ReplicatedStorage:WaitForChild("HumansUnlocked")
local map = game.Workspace:FindFirstChild(game.ServerStorage.Events.MatchStart.Event:Wait(), true)
local humansRecurringSpawn = map:FindFirstChild("HumansRecurring", true)
local orcsRecurringSpawn = map:FindFirstChild("OrcsRecurring", true)
local humansUnlocked = map:FindFirstChild("HumansUnlocked", true)
local orcsUnlocked = map:FindFirstChild("OrcsUnlocked", true)
local waypoints = map:FindFirstChild("Pathpoints", true)
local lastPos
local animPlaying = false
function spawnNPC(npcName, team)
local npc
local spawner
if team == "human" then
npc = game.ReplicatedStorage.HumansUnlocked:FindFirstChild(npcName):Clone()
npc.Parent = humansUnlocked
for i, spawner in pairs(humansRecurringSpawn:GetChildren()) do
if spawner.Name == npcName then
npc:PivotTo(spawner.CFrame)
end
end
elseif team == "orc" then
npc = game.ReplicatedStorage.OrcsUnlocked:FindFirstChild(npcName):Clone()
npc.Parent = orcsUnlocked
for i, spawner in pairs(orcsRecurringSpawn:GetChildren()) do
if spawner.Name == npcName then
npc:PivotTo(spawner.CFrame)
end
end
end
-- Get Humanoid and Set Network Owner for less lag
local humanoid = npc:WaitForChild("Humanoid")
local hrp = npc:WaitForChild("HumanoidRootPart")
hrp:SetNetworkOwner(nil)
-- Establish Raycasting for the npc
local rayParams = RaycastParams.new()
rayParams.FilterType = Enum.RaycastFilterType.Exclude
rayParams.FilterDescendantsInstances = {npc}
-- Load Animations for the NPC
local walkAnim = humanoid.Animator:LoadAnimation(script.WalkAnim)
local attackAnim = humanoid.Animator:LoadAnimation(script.Attack)
-- Functions for the NPC
local function canSeeTarget(target)
local orgin = hrp.Position
local direction = (target.HumanoidRootPart.Position - hrp.Position).Unit * RANGE
local ray = workspace:Raycast(orgin, direction, rayParams)
if ray and ray.Instance then
if ray.Instance:IsDescendantOf(target) then
return true
else
return false
end
else
return false
end
end
local function findTarget()
local enemies
if team == "orc" then
enemies = humansUnlocked
elseif team == "human" then
enemies = orcsUnlocked
end
local targets = {}
for _, child in ipairs(enemies:GetChildren()) do
if child:IsA("Model") and child:FindFirstChild("Humanoid").Health > 0 then
table.insert(targets, child)
end
end
local players = game.Players:GetPlayers()
local maxDistance = RANGE
local nearestTarget
for i, player in pairs(players) do
if player.Character and player.Team.TeamColor ~= npc.Team.TeamColor and player.Character.Humanoid.Health > 0 then
table.insert(targets, player)
end
end
for i, item in pairs(targets) do
if item.Team.TeamColor ~= npc.Team.TeamColor then
if item:isA("Player") then
local target = item.Character
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and canSeeTarget(target) then
nearestTarget = target
maxDistance = distance
end
else
local target = item
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and canSeeTarget(target) then
nearestTarget = target
maxDistance = distance
end
end
end
end
return nearestTarget
end
local function getPath(destination)
local path = PathfindingService:CreatePath(pathParams)
path:ComputeAsync(hrp.Position, destination.Position)
return path
end
local function attack(target)
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
local debounce = false
if distance > 7 then
humanoid:MoveTo(target.HumanoidRootPart.Position)
else
if debounce == false and humanoid.Health > 0 then
debounce = true
npc.Head.AttackSound:Play()
attackAnim:Play()
target.Humanoid.Health -= DAMAGE
task.wait(0.5)
debounce = false
end
end
end
local function walkTo(destination)
local path = getPath(destination)
if path.Status == Enum.PathStatus.Success then
for i, waypoint in pairs(path:GetWaypoints()) do
path.Blocked:Connect(function()
path:Destroy()
end)
if animPlaying == false then
walkAnim:Play()
animPlaying = true
end
attackAnim:Stop()
local target = findTarget()
if target and target.Humanoid.Health > 0 then
lastPos = target.HumanoidRootPart.Position
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
if distance <= 7 then
walkAnim:Stop()
animPlaying = false
end
attack(target)
--break
else
if waypoint.Action == Enum.PathWaypointAction.Jump then
humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
if lastPos then
humanoid:MoveTo(lastPos)
--humanoid.MoveToFinished:Wait()
lastPos = nil
--break
else
wait(0.1)
humanoid:MoveTo(waypoint.Position)
humanoid.MoveToFinished:Connect(function()
wait(0.2)
end)
end
end
end
else
return
end
end
local lastWaypoint = {}
local function patrol()
while humanoid.Health > 0 do
wait(0.02)
print("printing")
local waypoints = waypoints:GetChildren()
if team == "orc" then
for waypoint = 2, #waypoints do
if waypoints[waypoint] ~= lastWaypoint[npc] and humanoid.MoveDirection.Magnitude == 0 then
walkTo(waypoints[waypoint])
lastWaypoint[npc] = waypoints[waypoint]
end
end
elseif team == "human" then
for waypoint = (#waypoints - 1), 1, - 1 do
if waypoints[waypoint] ~= lastWaypoint[npc] and humanoid.MoveDirection.Magnitude == 0 then
walkTo(waypoints[waypoint])
lastWaypoint[npc] = waypoints[waypoint]
end
end
end
end
end
while task.wait(0.02) and humanoid.Health > 0 do
print("running")
patrol()
end
end
local matchInProgress = false
function main()
print("Match Started")
matchInProgress = true
while matchInProgress do
wait(5)
for i, spawners in pairs(humansRecurringSpawn:GetChildren()) do
task.spawn(function()
spawnNPC(spawners.Name, "human")
end)
end
for i, spawners in pairs(orcsRecurringSpawn:GetChildren()) do
task.spawn(function()
spawnNPC(spawners.Name, "orc")
end)
end
wait(40)
end
end
game.ServerStorage.Events.MatchStart.Event:Connect(main())
game.ServerStorage.Events.MatchEnd.Event:Connect(function()
matchInProgress = false
end)