Hey, I’ve made an entity system that can handle around 400-500 enemies before fps starts to decrease horribly and cpu and ping go all the way up. I’m trying to figure out if there’s a way I can decrease the CPU from spiking up randomly and prevent my ping from going high.
The only positive about this system at the moment is theres barely any gaps between enemies and the recv is low.
If anyone has any suggestions,tips,etc let me know as I really need it and can’t find anything that will work for my system.
Server Sided Script:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Nodes = workspace.BaseplateMap.Nodes
local Modules = ReplicatedStorage.Modules
local Events = ReplicatedStorage.Event
local EnemyInfo = require(Modules.EnemyInfo)
local Percision = 10^2
local counter = 0
local StartTime = workspace:GetServerTimeNow()
local enemy = {}
local currentenemies = {}
function enemy.ReturnEnemies()
return currentenemies -- returns the enemy table
end
function enemy.Spawn(name)
counter += 1
local EnemyTable = {
["Name"] = name;
["ID"] = counter;
["ModelID"] = EnemyInfo[name].ModelID;
["CFrame"] = CFrame.new(workspace.BaseplateMap.Start.Position,workspace.BaseplateMap.Nodes[1].Position);
["Node"] = 1;
["Path"] = 1;
["Speed"] = EnemyInfo[name].Speed;
["Health"] = EnemyInfo[name].Health;
["MaxHealth"] = EnemyInfo[name].MaxHealth;
["Buffs"] = EnemyInfo[name].Buffs
}
currentenemies[counter] = EnemyTable
coroutine.wrap(ServerSidedMovement)(counter,workspace:GetServerTimeNow())
end
function ServerSidedMovement(EnemyID,EnemySpawnTime)
local Connection
local EnemyTable = currentenemies[EnemyID]
local SentString = string.pack("BB",EnemyTable.ModelID,EnemyTable.Path)
Events.SpawnEnemy:FireAllClients(SentString)
if EnemyTable == nil then return end
local Start = workspace.BaseplateMap.Start
for index,value in ipairs(Nodes:GetChildren()) do
local ReachedWaypoint = false
local NextWaypoint = Nodes:FindFirstChild(tostring(index))
local CurrentWaypoint = Nodes:FindFirstChild(tostring(index - 1))
if CurrentWaypoint == nil then
CurrentWaypoint = Start
end
local timehappened = 0
local function MoveEnemy(DeltaTime)
local Delta = workspace:GetServerTimeNow() - EnemySpawnTime
EnemySpawnTime = workspace:GetServerTimeNow()
if CurrentWaypoint ~= Nodes:FindFirstChild(tostring(#Nodes:GetChildren())) and ReachedWaypoint == false then
timehappened += DeltaTime
local Speed = EnemyTable.Speed
local distance = (EnemyTable.CFrame.Position - NextWaypoint.Position).Magnitude
local Time = distance/Speed
local alpha = (timehappened/Time) % 1
local Lerp = EnemyTable.CFrame:Lerp(NextWaypoint.CFrame,Delta*Speed/distance)
EnemyTable.CFrame = CFrame.new(Lerp.Position,NextWaypoint.Position)
local MagChecking = (EnemyTable.CFrame.Position - NextWaypoint.Position).Magnitude
if MagChecking <= 0.4 then
ReachedWaypoint = true
Connection:Disconnect()
end
end
end
Connection = RunService.Heartbeat:Connect(MoveEnemy)
repeat task.wait() until ReachedWaypoint
end
Connection:Disconnect()
Events.EnemyDie:FireAllClients(EnemyID,EnemyTable.Health,true)
end
return enemy
ClientSided
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local EnemiesFolder = workspace.Enemy
local RunService = game:GetService("RunService")
local Percision = 10^2
local players = game:GetService("Players")
local player = players.LocalPlayer
local GUI = player.PlayerGui
local LastUpdate = workspace:GetServerTimeNow()
local Nodes = workspace.BaseplateMap.Nodes
local Enemies = ReplicatedStorage.Enemies
local Events = ReplicatedStorage.Event
local counter = 0
function quadBezier(t, p0, p1, p2)
return (1 - t)^2 * p0 + 2 * (1 - t) * t * p1 + t^2 * p2
end
function ClientEnemyMovement(Enemy,EnemySpawnTime)
local End = workspace.BaseplateMap.End
local Connection
local PrimaryPart = Enemy.PrimaryPart
if Enemy == nil or Enemy.PrimaryPart == nil then return end
local EnemySpawnTime = EnemySpawnTime
for index,value in ipairs(Nodes:GetChildren()) do
local ReachedWaypoint = false
local NextWaypoint = Nodes:FindFirstChild(tostring(index + 1))
local CurrentWaypoint = Nodes:FindFirstChild(tostring(index))
if NextWaypoint == nil then
NextWaypoint = End
end
local timehappened = 0
local function MoveEnemy(DeltaTime)
local Delta = workspace:GetServerTimeNow() - EnemySpawnTime
EnemySpawnTime = workspace:GetServerTimeNow()
if CurrentWaypoint ~= Nodes:FindFirstChild(tostring(#Nodes:GetChildren())) and ReachedWaypoint == false then
timehappened += Delta
local Speed = Enemy:GetAttribute("Speed")
local distance = (PrimaryPart.Position - NextWaypoint.Position).Magnitude
local Time = distance/Speed
local alpha = (timehappened/Time) % 1
local Lerp = PrimaryPart.CFrame:Lerp(NextWaypoint.CFrame,Delta*Speed/distance)
local BigCFrame = CFrame.new(Lerp.Position,NextWaypoint.Position)
PrimaryPart:PivotTo(BigCFrame)
local MagChecking = (PrimaryPart.Position - NextWaypoint.Position).Magnitude
if MagChecking <= 0.4 then
ReachedWaypoint = true
Connection:Disconnect()
end
end
end
Connection = RunService.Heartbeat:Connect(MoveEnemy)
repeat task.wait() until ReachedWaypoint
end
Connection:Disconnect()
end
Events.SpawnEnemy.OnClientEvent:Connect(function(SentString)
counter += 1
local unpackedstring = {string.unpack("BB",SentString)}
unpackedstring[#unpackedstring] = nil
local ModelID = unpackedstring[1]
local PathNumber = unpackedstring[2]
if not EnemiesFolder:FindFirstChild(counter) then
for i,v in pairs(Enemies:GetChildren()) do
if v:GetAttribute("ModelID") == ModelID then
local lilbuddy = Enemies[tostring(v)]:Clone()
for i, v in pairs(v:GetChildren()) do
if v:IsA("BasePart") or v:IsA("MeshPart") then
v.CollisionGroup = "Mobs"
end
end
lilbuddy:SetAttribute("EnemyID",counter)
lilbuddy.Parent = EnemiesFolder
lilbuddy.PrimaryPart.CFrame = workspace.BaseplateMap.Start.CFrame + Vector3.new(0, (lilbuddy.PrimaryPart.Size.Y/2 - 1), 0)
coroutine.wrap(ClientEnemyMovement)(lilbuddy,workspace:GetServerTimeNow())
end
end
end
end)
Also I’d appreciate it if you don’t recommend me to use humanoids,tweenservice,or any open source modules like matter that do the work for you. Thank you