Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Improving RenderStepped CFraming preformance of many parts?

Asked by
Nickoakz 231 Moderation Voter
9 years ago

I have a script that's rendering many parts at a time, I'm just asking, is my math horrible at performance? I have a beefy CPU to generate this math, just wondering if there's a more efficient way to do it to have it run on weak CPU's better.

diam=34
blocks=36
plz=game.Players.LocalPlayer
game:GetService("RunService").RenderStepped:connect(function()
    if model==nil then
        model=Instance.new("Model", workspace)
        model.Archivable=false
    else
        model:ClearAllChildren()
    end 
    for r=1,blocks do
        bl=Instance.new("Part",model)
        bl.FormFactor="Custom"
        bl.Anchored=true
        bl.Size=Vector3.new(1,1,1)
        plc=(plz.Character.Torso.CFrame*CFrame.Angles(0,math.rad(90),0)):toWorldSpace(CFrame.new() + 
            (CFrame.new() * CFrame.Angles(math.rad(r*(360/blocks)),0,0)).lookVector * 
        (.5*diam))
        bl.CFrame=plc
    end
    wait()
end)

3 answers

Log in to vote
1
Answered by
Unclear 1776 Moderation Voter
9 years ago

Optimization 101: don't do what you don't have to. If you can do a calculation or operation beforehand without sacrificing accuracy, do so.

If you can simplify an expression, do so.

A lot of your code doesn't actually produce any noticeable effect and can be done simpler.

Also, while working with CFrames, please never use math.deg. Angles are always measured in radians, both on ROBLOX and in real life. Degrees are just mythical creatures that should be killed and forever forgotten.

Below, I have reduced the amount of calculations and operations down to what I believe to be an acceptable level without reducing clarity.

-- Settings
local diameter = 34
local numberOfBlocks = 36
-- End Settings

local player = game.Players.LocalPlayer
local blocks = { }
local model

-- Preliminary math
local delta = 2*math.pi/numberOfBlocks
local radius = 0.5*diameter

function createParts()
    model = Instance.new("Model", workspace)
    model.Archivable = false
    for index = 1, numberOfBlocks do
        local block = Instance.new("Part", model)
        block.FormFactor = Enum.FormFactor.Custom
        block.Anchored = true
        block.Size = Vector3.new(1, 1, 1)
        blocks[#blocks + 1] = block
    end
end

function update()
    local root = player.Character.Torso.CFrame*CFrame.Angles(0, 0.5*math.pi, 0)
    for index = 1, numberOfBlocks do
        local block = blocks[index]
    -- Set a pivot, then offset by a certain amount to produce a circle is what you're trying.
    -- No need to make your math any more complicated than that.
        block.CFrame = root*CFrame.Angles(index*delta, 0, 0)*CFrame.new(0, 0, radius)
    end
end

createParts()
game:GetService("RunService").RenderStepped:connect(update)
Ad
Log in to vote
0
Answered by 9 years ago

Instead of constantly creating and removing the parts, just create the parts once and then update the positions only. That way you have less code that is looping.

First, you have to move the static code to the top of the loop, like so:

 --I added a local in front of the variables because it uses less memory and the script can access them faster
local diam=34
local blocks=36
local plz=game.Players.LocalPlayer

local model=Instance.new("Model", workspace)
model.Archivable=false

The model is only going to be made once, so that's why we don't need to have it in a loop.

Now, we have a loop that is creating blocks constantly, but we only want it to create the blocks once so that the loop can just access the blocks and change their positions without having to create more blocks. To do this, we'll need to know how to use Tables

Tables are basically arrays that can be used to hold items. So in our case, that table will hold all the bricks that will be in the circle, like so:

--I'm following your syntax formatting. This isn't the way that I normally write syntax (e.g. BlockTable = {} or for i = 1, blocks do)
local blockTable={}
for r=1,blocks do
    local bl=Instance.new("Part",model)
    bl.FormFactor="Custom"
    bl.Anchored=true
    bl.Size=Vector3.new(1,1,1)
    table.insert(blockTable,bl)
end

The above code will create all the blocks and insert them into a table called "blockTable"

This allows us to access the table from the loop and change their positions, like so:

--I removed the wait() at the end of the loop because that's a redundant wait(). It won't do anything
game:GetService("RunService").RenderStepped:connect(function()
    for r, bl in pairs(blockTable) do --This is a special for loop that is used to iterate through tables. "r" is the index, which is the position of the element in the table, and "bl" is the element itself
        local plc=(plz.Character.Torso.CFrame*CFrame.Angles(0,math.rad(90),0)):toWorldSpace(CFrame.new() + 
            (CFrame.new() * CFrame.Angles(math.rad(r*(360/blocks)),0,0)).lookVector * 
        (.5*diam))
        bl.CFrame=plc
    end
end)

Final code:

local diam=34
local blocks=36
local plz=game.Players.LocalPlayer

local model=Instance.new("Model", workspace)
model.Archivable=false

local blockTable={}
for r=1,blocks do
    local bl=Instance.new("Part",model)
    bl.FormFactor="Custom"
    bl.Anchored=true
    bl.Size=Vector3.new(1,1,1)
    table.insert(blockTable,bl)
end

game:GetService("RunService").RenderStepped:connect(function()
    for r, bl in pairs(blockTable) do
        local plc=(plz.Character.Torso.CFrame*CFrame.Angles(0,math.rad(90),0)):toWorldSpace(CFrame.new() + 
            (CFrame.new() * CFrame.Angles(math.rad(r*(360/blocks)),0,0)).lookVector * 
        (.5*diam))
        bl.CFrame=plc
    end
end)

Hope this helped!

Log in to vote
0
Answered by
BlackJPI 2658 Snack Break Moderation Voter Community Moderator
9 years ago

Removing and creating that many instances every render frame could be very hard on weaker processors. I recommend just updating the CFrame of all these blocks every render frame to help increase performance.

I also believe that making functions for reused code makes it more efficient, but even if it doesn't It still makes the script cleaner and easier to read.

local blocks=  {}
local diam = 34
local blocks = 36
local model = Instance.new("Model", workspace)
local plz = game.Players.LocalPlayer

model.Archivable=false

local function CalculateCFrame(r)
    return (plz.Character.Torso.CFrame*CFrame.Angles(0,math.rad(90),0)):toWorldSpace(CFrame.new() + (CFrame.new()*CFrame.Angles(math.rad(r*(360/blocks)),0,0)).lookVector*(.5*diam))
end

local function CreatePart(r)
    bl=Instance.new("Part",model)
    bl.FormFactor="Custom"
    bl.Anchored=true
    bl.Size=Vector3.new(1,1,1)
    bl.CFrame=CalculateCFrame(r)
    table.insert(parts, bl)
end

for r=1,blocks do
    CreatePart(r)
end

game["Run Service"]:RenderStepped:connect(function()
    for r, block in ipairs (blocks) do
        block.CFrame = CalculateCFrame(r)
    end
end)

Answer this question