Ad
Log in to vote
0

How do i optimize my entity system?

Asked by 14 days ago

I've made this entity system for a game I'm making, and it hold around 300-600 enemies before lagging anyone know how to optimize it more (the enemies are on client server sends client position to update it)

server:

local mob = {}
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Events = ReplicatedStorage:WaitForChild("Events")
local LastUpdate = tick()
local UpdateDT = 0.1
local ClientInfo = {}
shared["Positions"] = {}
local MobsFolder =ReplicatedStorage:WaitForChild("Mobs")

local mysteryMob = {
    ["Mystery"] = {MobsFolder:WaitForChild("Zombie"), MobsFolder:WaitForChild("Speedy"), MobsFolder:WaitForChild("Boss"), MobsFolder:WaitForChild("Spy")}
}

game:GetService("RunService").Heartbeat:Connect(function(DeltaTime)
    local map = workspace:WaitForChild("Map") 

    local success, errorMsg = pcall(function()
        for number, data in pairs(shared["Positions"]) do 
            if not data or not number or not data[3] then continue end          
            local CurrentWaypoint = map.Waypoints:FindFirstChild(data[1])
            local OldWaypoint = map.Waypoints:FindFirstChild(data[1]-1) or map.Start

            if not CurrentWaypoint or data[2].Y <= 0 then 
                if mysteryMob[data.Name] and CurrentWaypoint then
                    mob.Mystery(data,  OldWaypoint.CFrame:Lerp(CurrentWaypoint.CFrame, data[3]),  data[3], data[1])
                end
                if not CurrentWaypoint then
                    map.Base.Humanoid:TakeDamage(data[2].Y)
                end
                ClientInfo[number] = {Dead = true}
                Events.UpdatePosition:FireAllClients(ClientInfo)
                shared["Positions"][number] = nil
                shared["currentMobs"] -= 1

                continue
            end

            local distance = (OldWaypoint.Position - CurrentWaypoint.Position).Magnitude
            data[3] += DeltaTime * data[2].X/50 / distance
            if data[3] >= 1 then
                data[1] += 1
                data[3] = 0
            end
            ClientInfo[number] = {Vector2int16.new(math.floor(CurrentWaypoint.Position.X*50), math.floor(CurrentWaypoint.Position.Z*50)), data[2].Y}
        end
    end)

    if not success then
        warn(errorMsg)
    end
    if success and tick() - LastUpdate >= UpdateDT then
        LastUpdate = tick()
        Events.UpdatePosition:FireAllClients(ClientInfo)
    end
end)


local num = 0 
shared["currentMobs"] = 0
function mob.Spawn(name, quantity, map)
    local Exists = ReplicatedStorage.Mobs:FindFirstChild(name)

    if Exists then 
        for i = 1, quantity do 
            num += 1
            if shared["currentMobs"] < 0 then
                shared["currentMobs"] = 0
            end
            shared["currentMobs"] += 1
            shared["Positions"][num] = {1, Vector2int16.new(Exists.Config.Speed.Value*50, math.round(Exists.Config.Health.Value)), 0,}
            Events.Render:FireAllClients(name, num, false)
            task.wait(0.25) 
        end
    end
end

function mob.Mystery(mob, cframe, moved, waypoint)
    local mystery = ReplicatedStorage.Mobs.Mystery  

    if mysteryMob[tostring(mob.Name)] then
        local Table =  mysteryMob[tostring(mob.Name)]
        local newMob = Table[math.random(1, #Table)]
        local oldwaypoint = workspace.Map.Waypoints:FindFirstChild(waypoint-1) or workspace.Map.Start
        local Waypoint =  workspace.Map.Waypoints:FindFirstChild(waypoint)
        shared["currentMobs"] += 1
        shared["Positions"][num] = {waypoint, Vector2int16.new(newMob.Config.Speed.Value*50, math.round(newMob.Config.Health.Value)), moved,}
        print(shared["Positions"][num].Moved)
        Events.Render:FireAllClients(newMob.Name, num, false, cframe)
    end
end

return mob

Client:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Events = ReplicatedStorage:WaitForChild("Events")

local LastUpdate = tick()
local ud = 0.0085

shared["Enemies"] = {}
shared["Units"] = {}

local positions = {}
local UnitPositions = {}

local map = workspace:WaitForChild("Map")
local base = map:WaitForChild("Base")

local PS = game:GetService("PhysicsService")

local function animation(object, anim)
    Events.AnimateZombie:Fire(object, anim)
end

Events.UpdatePosition.OnClientEvent:Connect(function(info, unitInfo)
    if info then
        positions = info
    elseif unitInfo then
        UnitPositions = unitInfo
    end
end)


local function moveEnemy(deltaTime)
    for Enemyobject, data in pairs(shared["Enemies"]) do 
        if Enemyobject and positions[data] then                     
            local pos = positions[data]         
            local Paosition = pos[1]
            if not Paosition or not Paosition.X or not Paosition.Y then 
                shared["Enemies"] [Enemyobject] = nil
                Enemyobject:Destroy()
                continue
            end
            Enemyobject.Config.Health.Value = pos[2]
            local Position = Vector3.new(Paosition.X/50, Enemyobject.PrimaryPart.Position.Y, Paosition.Y/50)
            local Distance = (Enemyobject.PrimaryPart.Position - Position).Magnitude

            local speed = Enemyobject.Config.Speed.Value

            local cframe = CFrame.new(Paosition.X/50, Enemyobject.PrimaryPart.Position.Y, Paosition.Y/50)

            if Distance > 1 then
                Enemyobject.HumanoidRootPart.CFrame = CFrame.lookAt(    Enemyobject.HumanoidRootPart.Position, Position)
            end
            Enemyobject:PivotTo(Enemyobject.PrimaryPart.CFrame:Lerp(cframe, deltaTime*speed/Distance))      
        end
    end
end

local function moveUnit(deltaTime)
    for UnitObject, data in pairs(shared["Units"] ) do 
        if UnitObject and UnitPositions[data] then                  
            local pos = UnitPositions[data]         
            local Paosition = pos[1]
            if not Paosition or not Paosition.X or not Paosition.Y then 
                shared["Units"] [UnitObject] = nil
                UnitObject:Destroy()
                continue
            end
            UnitObject.Config.Health.Value = pos[2]
            local Position = Vector3.new(Paosition.X/50, UnitObject.PrimaryPart.Position.Y, Paosition.Y/50)
            local Distance = (UnitObject.PrimaryPart.Position - Position).Magnitude

            local speed = UnitObject.Config.Speed.Value

            local cframe = CFrame.new(Paosition.X/50, UnitObject.PrimaryPart.Position.Y, Paosition.Y/50)

            if Distance > 1 then
                UnitObject.HumanoidRootPart.CFrame = CFrame.lookAt(UnitObject.HumanoidRootPart.Position, Position)
            end
            UnitObject:PivotTo(UnitObject.PrimaryPart.CFrame:Lerp(cframe, deltaTime*speed/Distance))        
        end
    end
end

game:GetService("RunService").Heartbeat:Connect(function(deltaTime)
    if tick() - LastUpdate < ud then 
        return
    end 
    LastUpdate = tick()
    moveUnit(deltaTime)
    moveEnemy(deltaTime)
end)

Events.Render.OnClientEvent:Connect(function(name, EnemyNumber, unit, cframe)
    if not unit then    
        local map = workspace:WaitForChild("Map")
        local start = map:WaitForChild("Start")

        local enemy = ReplicatedStorage.Mobs:FindFirstChild(name):Clone()
        enemy.Parent = workspace.Mobs
        if not enemy.PrimaryPart then
            enemy.PrimaryPart = enemy.HumanoidRootPart
        end
        enemy.PrimaryPart.Anchored = true
        enemy.PrimaryPart.CanCollide = false

        local zombieTag = Instance.new("BoolValue")
        zombieTag.Name = "ZombieTag"
        zombieTag.Parent = enemy
        for i, v in pairs(enemy:GetChildren()) do 
            if v:IsA("BasePart") then 
                PS:SetPartCollisionGroup(v, "Mob")
            end
        end
        enemy.PrimaryPart.CFrame = cframe or start.CFrame + Vector3.new(0, (enemy.PrimaryPart.Size.Y/2 - 1), 0)

        shared["Enemies"] [enemy] = EnemyNumber 
        animation(enemy, "Walk")
    else
        local map = workspace:WaitForChild("Map")
        local start = map:WaitForChild("End")

        local unit = ReplicatedStorage.Units:FindFirstChild(name):Clone()
        unit.Parent = workspace.Units
        if not unit.PrimaryPart then
            unit.PrimaryPart = unit.HumanoidRootPart
        end
        unit.PrimaryPart.Anchored = true
        unit.PrimaryPart.CanCollide = false

        local unitTag = Instance.new("BoolValue")
        unitTag.Name = "UnitTag"
        unitTag.Parent = unit
        for i, v in pairs(unit:GetChildren()) do 
            if v:IsA("BasePart") then 
                PS:SetPartCollisionGroup(v, "Unit")
            end
        end
        unit.PrimaryPart.CFrame = cframe or start.CFrame + Vector3.new(0, (unit.PrimaryPart.Size.Y/2 - 1), 0)

        shared["Units"] [unit] = EnemyNumber 
    end
end)

Answer this question