Paul
Paul

Reputation: 1327

Improve performance using lua and Roblox Studio

I have finally finished my first script using lua and Roblox studio. The goal was to have a set of tiles change colour when the player steps on it.

Here is my code:

local parts = {}
for k, v in pairs(game.Workspace:GetDescendants()) do
    if string.sub (v.name, 1, 4) == "Part"  then
        table.insert(parts, v)
    end
end

local char = workspace:WaitForChild("localPlayer") 

local hrp = char:WaitForChild("HumanoidRootPart")

local newThread = coroutine.create(function()

game:GetService("RunService").Heartbeat:Connect(function()
    local charpos = hrp.Position

    for k, v in pairs (parts)do
        if (charpos - v.CFrame.Position).magnitude <= 6 then
            local pos = v.CFrame.Position
            for k, v in pairs(parts) do
                if v.CFrame.Position.X == pos.X or v.CFrame.Position.Z == pos.Z then
                    v.BrickColor = BrickColor.new("Really red")
                    print("touching")
                end
            end
            return
        else
            v.BrickColor = BrickColor.new("Medium stone grey")
            print("not touching")
        end
    end
end)

end)

coroutine.resume(newThread)

This works:

enter image description here

But my project needs more tiles and more colors. When I increase the number of platforms etc.. the program becomes very laggy.

enter image description here

The gif doesn't really show how laggy, but it gets worse and worse and after about a minute of playing you can hardly control the player effectively.

As you can see, I tried putting my function inside a co-routine but that didn't help. I am very new to lua and trying making games so I really don't know how to improve performance. The fact that the lagginess gets worse and worse seems to suggest memory is not being freed effectively? I assumed this happened automatically. Anyway, any help much appreciated.

After suggestions, I have tried this:

Hi, I have tried this:

    local Platform = {}
    local maPart = Platform.part
    local function makePart(pX,pY,pZ)
        maPart = Instance.new("Part", workspace)
        maPart.Position = Vector3.new(pX,pY,pZ)
        maPart.Size = Vector3.new(10,1,10)
        return maPart
    end

    local columns = {}
    local rows = {}

    for i = 1, 12 do
        columns[i] = rows
        table.insert(columns, rows)
        for j = 1, 12 do
            maPart = makePart(i*16,0,j*16)
            rows[j] = maPart
            table.insert(rows, maPart)
        end
    end

    columns[1].[1].BrickColor = BrickColor.new("Really blue")

As an exercise to see if I can get this new concept for me of 'multi dimensional arrays' to work. The last line doesn't work. How would I access an element inside an array inside an array? tx

Upvotes: 1

Views: 1167

Answers (2)

Kylaaa
Kylaaa

Reputation: 7188

Your function isn't inside the coroutine, only the connection to the signal is. But, since the heartbeat code is running every single frame, using a coroutine to dispatch the work to a different thread that won't start until the next frame won't help much. So instead of threading, try to look for ways to minimize the computational effort of the function.

Print statements can slow things down, so comment those out when you know the logic works. Calculations with square roots are expensive, so I think the best optimization is to minimize the number of distance checks.

I would recommend making the Heartbeat function act as a more reliable TouchEnded handler, but only have it do work on platforms that know they have a player touching them. Then you can use a part's Touched handler for knowing which platforms have players.

-- initialize some script globals
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

-- grab all the platforms and create a table of custom objects with data we care about
local platforms = {}
for _, part in ipairs(game.Workspace:GetDescendants()) do
    if string.sub (v.name, 1, 4) ~= "Part"  then
        continue
    end

    local platformData = {
        Part = part, -- the original object
        Touches = {}, -- a map of players actively touching it
    }

    -- initialize any events on these parts
    part.Touched:Connect(function(otherPart)
        -- when touched, check which player it is, and hold onto that information
        local player = Players:GetPlayerFromCharacter(part.Parent)
        if not player then
            warn(string.format("unexpected object touched a platform. Ignoring %s", part.Parent.Name))
            return
        end

        platformData.Touches[player.PlayerId] = player
    end)

    -- hold onto this data
    table.insert(platforms, platformData)
end

-- make a function that updates colors
RunService.Heartbeat:Connect(function()
    for _, platform in ipairs(platforms) do
        local isTouched = next(platform.Touches) ~= nil

        -- quick escape for inactive platforms
        if not isTouched then
            continue
        end

        -- check if the previous players are still touching it
        isTouched = false
        for id, player in pairs(platform.Touches) do
            local platPos = platform.Part.Position
            local hrp = player.Character.PrimaryPart
            local charPos = hrp.Position
            local dist = (platPos - charPos).magnitude

            if dist < 6 then
                isTouched = true
            else
                -- this player is no longer touching, remove them
                platform.Touches[id] = nil
            end
        end

        -- update the color of the platforms
        if isTouched then
            platform.Part.BrickColor = BrickColor.new("Really red")
        else
            platform.Part.BrickColor = BrickColor.new("Really blue")
        end
    end
end)

I hope this helps! Good luck!

Upvotes: 0

Vlad
Vlad

Reputation: 5857

Minor change - move out the loop the construction of new BrickColor. Its value doesn't change across unaffected parts, no reasons to repeatedly create it.

And see if printing lots of debugging information affects the performance, so comment out prints.

Secondly, probably you should reorganize the grid of the blocks into two-dimentional array. So then you don't have to scan all the parts to find the ones that has the same X/Z coordinate. This also will give you the way to quickly find the closest brick, it's trivial on a regular grid.

Upvotes: 1

Related Questions