its the main part of my game
( ✦ ) Brick Inc. - Roblox
check it out if you want to
also @Tomi1231
microprofile-20250304-133504.txt (9.0 MB)
Okay so what weve learned through this post so far is that the TweenService shouldnt play a major role in causing lag when used normally. In this case however, were spamming it.
Let me adjust my question according to this turn:
Can a Tween (Instance) be re-used? This way, TS:Create() wouldn’t spam new instances every few milli-seconds.
Are the parts anchored???
yep they are, since i didnt want to use the engine’s physics
Why do you have:
do
end
at the childadded part?
I honestly dont know why.
There was a time where I was having issues with memory leaks and I think thats what I tried using to solve it.
This script is kinda old, you see.
Now I know that changes absolutely nothing cus its already in a smaller “scope”? Idk what the correct word for you-know-what is
(I removed this now)
ngl it’s probably the 200 new parts being created every seccond, and you can also instead of doing coroutines and stuff you can do task.spawn and you dont need to make a new local function animate each time just put animate.
Like I said, when I turn off the animations the game runs smoothly, I think the main issue is the TweenService, specifically the “Bounce” Easing style, I tried using Sine (and Linear), those seem to be running much more smoothly.
Also I can show you my “SpawnBrick Code”
local player = game:GetService("Players").LocalPlayer
local BricksFolder = game:GetService("Workspace"):WaitForChild("Bricks"):WaitForChild(player.Name)
local ClientBricks = game:GetService("ReplicatedStorage"):WaitForChild("ClientBricks")
local Enabled = player:WaitForChild("Settings"):WaitForChild("Bricks")
local ClientBricksWSFolder = workspace:WaitForChild("ClientBricks")
local random = math.random
-- Function --
local ServerBricksTable = {}
local ClientBrickTable = {}
local function findIndex(table, value)
for index, valueB in table do
if value == valueB then
return index
end
end
end
-- Get a random character
local function showBrick(Brick: Instance)
task.desynchronize()
if not Brick:IsA("CFrameValue") then return end
if Brick == nil then return end
local Identifier = random(0, 1000000000)
ServerBricksTable[Identifier] = Brick
task.synchronize()
local ClientBrick = ClientBricks[Brick.Name]:Clone()
ClientBrickTable[Identifier] = ClientBrick
ClientBrick:PivotTo(Brick.Value)
ClientBrick.Transparency = 0
ClientBrick.Parent = ClientBricksWSFolder
end
-- Removing Bricks --
local function RemoveBrick(Brick: Instance)
task.desynchronize()
if not Brick:IsA("CFrameValue") then return end
local Identifier = findIndex(ServerBricksTable, Brick)
task.synchronize()
ClientBrickTable[Identifier]:Destroy()
ClientBrickTable[Identifier] = nil
ServerBricksTable[Identifier] = nil
end
-- Handling the connection --
local Connection = BricksFolder.DescendantAdded:Connect(showBrick)
local Connection2 = BricksFolder.DescendantRemoving:Connect(RemoveBrick)
while true do task.wait(2)
if Enabled.Value == true then
local PastConnection = Connection
local PastConnection2 = Connection2
Connection = BricksFolder.DescendantAdded:Connect(showBrick)
Connection2 = BricksFolder.DescendantRemoving:Connect(RemoveBrick)
PastConnection:Disconnect()
PastConnection2:Disconnect()
end
if Enabled.Value == false then
Connection:Disconnect()
Connection2:Disconnect()
for _, Brick in ClientBrickTable do
Brick:Destroy()
end
for _, Brick in ServerBricksTable do
Brick:Destroy()
end
ServerBricksTable = {}
ClientBrickTable = {}
end
end
Also ignore the comments, I just realised i forgot to remove some of them from when I was testing some functions
GPT optimized the script here
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Workspace = game:GetService("Workspace")
local player = Players.LocalPlayer
local toggle: BoolValue = player:WaitForChild("Settings"):WaitForChild("BrickAnimations")
local bricksFolder = Workspace:WaitForChild("ClientBricks")
-- Predefine TweenInfos
local FallTweenInfo = TweenInfo.new(1.25, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out)
local TransTweenInfo = TweenInfo.new(1, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out)
local function AnimateChild(child: Instance)
if not child:IsA("BasePart") then return end -- Ensure it's a part
child.Transparency = 1
child.Orientation = Vector3.new(0, math.random(0, 360), 0)
if child.Name == "BrickD" or child.Name == "BrickE" then
child.Orientation = Vector3.new(math.random(-25, 55), math.random(0, 45), math.random(-25, 65))
end
-- Store original position to avoid multiple lookups
local originalPosition = child.Position
child.Position = originalPosition + Vector3.new(0, 40, 0)
-- Use a single Tween call
local Tween = TweenService:Create(child, FallTweenInfo, {
Position = originalPosition,
Transparency = 0
})
Tween:Play()
-- Cleanup when finished
Tween.Completed:Wait()
Tween:Destroy()
if child.Name == "BrickD" or child.Name == "BrickE" then
child.Position = child.Position + Vector3.new(0, 2, 0)
end
end
bricksFolder.ChildAdded:Connect(function(child: Instance)
if toggle.Value then
task.spawn(AnimateChild, child) -- More efficient than coroutine
else
child.Transparency = 0
end
end)
bruh
I didnt reply immedietly cus I WAS ASKING THE GPT THE SAME THING
anyways thanks ima try that my gpt sucks
Wow the gpt actually cooked
the performance is much more stable now.
The biggest notable difference is that the gpt uses one tween instead of 2
Its still unplayably laggy but eh this’ll do for now
That didn’t work either, and when trying to open the original html on my pc, it crashes my firefox tab
And this is with a browser that doesn’t crash
But umm, no need to provide a micro profiler dump anymore, as you’ve posted your game’s link and I can look at the micro profiler that way
Cloning is indeed taking the most significant amount of time
You can avoid this by caching parts, and reusing them
Tweens do take a significant amount of time as well, but not much you can do about that, other than combining the transparency and position tween, as you’ve done
Sorry for the late reply, I was really busy with school.
How would I go about caching the parts/reusing them?
Caching them would be simple, but how would I reuse them?
Do I teleport them below the map once collected and beam them back up once needed?
Would I set up an array of the parts where I keep track of which parts are in use and which arent?
I dont think that’d be the best method so I’ll have to rely on some input from you here
It would basically involve either parenting the parts to nil, or teleporting them very far away (that might be more performant, not sure if it’s still the case). Then when you need to spawn a new part, rather than use cloning, you can one of those old part, change the material color and size, and move it to where the tween will start
Something like that would work
Ah thanks, Ill try making a system like that then.
The reparenting version works, but still causes lag as reparenting a thousand times per second isnt exactly efficient either.
Repositioning works, BUT:
The tweens cant be overwritten, which means that I cant reposition the bricks correctly as my scripts have to wait for the tweens to finish first.
Would it maybe be a good idea to put the two scripts into a common actor so that I can send shared tables of the TweenInstances around?
I ended up merging the two scripts since i didnt get shared tables
This works beautifully
Thanks so much
In theory you should not have to wait for the tween to end, as you should be using inactive parts
Tweening is not allowed in parallel, so you wont get any benefits from running it in parallel. In fact you’ll get worse performance because shared tables and other manners of sharing data across actors is slow. Currently, parallel lua on roblox can only really be applied to a very limited amount of tasks
Glad you eventually got something that’s more optimized :P
thats what Im doing. The problem is that the tweens are extremely dominant.
Meaning, if I teleport a brick very far away while a tween is playing, it’ll only get teleported there for a split second until it gets beamed to the next position of the tween. Same goes for transparency, so i cant just hide it.
Im not using parallel luau for my current solution at ALL, but my scripts are still parented to an actor. Could this also cause issues?
I’ll also attach my code here, if you’re interested.
local player = game:GetService("Players").LocalPlayer
local BricksFolder = game:GetService("Workspace"):WaitForChild("Bricks"):WaitForChild(player.Name)
local ClientBricks = game:GetService("ReplicatedStorage"):WaitForChild("ClientBricks")
local Enabled = player:WaitForChild("Settings"):WaitForChild("Bricks")
local ClientBricksWSFolder = workspace:WaitForChild("ClientBricks")
local random = math.random
local BrickEEffect = game:GetService("ReplicatedStorage"):WaitForChild("ClientBricks"):WaitForChild("BrickE"):WaitForChild("ParticleEmitter")
local BrickA = game:GetService("ReplicatedStorage"):WaitForChild("ClientBricks"):WaitForChild("BrickA")
local BrickB = game:GetService("ReplicatedStorage"):WaitForChild("ClientBricks"):WaitForChild("BrickB")
local BrickC = game:GetService("ReplicatedStorage"):WaitForChild("ClientBricks"):WaitForChild("BrickC")
local BrickD = game:GetService("ReplicatedStorage"):WaitForChild("ClientBricks"):WaitForChild("BrickD")
local BrickE = game:GetService("ReplicatedStorage"):WaitForChild("ClientBricks"):WaitForChild("BrickE")
local depositCFrame = CFrame.new(Vector3.new(9999999, -9999999, 9999999), Vector3.new(0, 0, -1))
local TweenService = game:GetService("TweenService")
local toggle: BoolValue = player:WaitForChild("Settings"):WaitForChild("BrickAnimations")
-- Animating --
local tweens = {}
local bricksFolder = workspace:WaitForChild("ClientBricks")
local FallTweenInfo = TweenInfo.new(1.25, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out)
local TransTweenInfo = TweenInfo.new(1, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out)
local function AnimateChild(child: Instance)
if not child:IsA("BasePart") then return end
child.Transparency = 1
child.Orientation = Vector3.new(0, random(0, 360), 0)
if child.Name == "BrickD" or child.Name == "BrickE" then
child.Orientation = Vector3.new(random(-25, 55), random(0, 45), random(-25, 65))
end
local originalPosition = child.Position
child.Position = originalPosition + Vector3.new(0, 40, 0)
local Tween = TweenService:Create(child, FallTweenInfo, {
Position = originalPosition,
Transparency = 0
})
tweens[#tweens+1] = {child, Tween}
Tween:Play()
if Tween then Tween:Destroy() end
if child.Name == "BrickD" or child.Name == "BrickE" then
child.Position = child.Position + Vector3.new(0, 2, 0)
end
end
local function animateBrick(child)
if toggle.Value then
task.spawn(AnimateChild, child)
else
child.Transparency = 0
end
end
-- Functions --
local ServerBricksTable = {}
local ClientBrickTable = {}
local ClientBrickAReserve = {}
local ClientBrickBReserve = {}
local ClientBrickCReserve = {}
local ClientBrickDReserve = {}
local ClientBrickEReserve = {}
local function destroy(Brick: Part)
if Brick == nil then return end
for index, brickAndTween in tweens do
if brickAndTween[1] == Brick then
brickAndTween[2]:Cancel()
brickAndTween[2]:Destroy()
Brick.CFrame = depositCFrame
table.remove(tweens, index)
return
end
end
Brick.CFrame = depositCFrame
end
local function registerBrickReserves()
for counter = 1, 900, 1 do
local Clone = BrickA:Clone()
Clone.CFrame = depositCFrame
Clone.Parent = ClientBricksWSFolder
ClientBrickAReserve[#ClientBrickAReserve+1] = Clone
end
for counter = 1, 900, 1 do
local Clone = BrickB:Clone()
Clone.CFrame = depositCFrame
Clone.Parent = ClientBricksWSFolder
ClientBrickBReserve[#ClientBrickBReserve+1] = Clone
end
for counter = 1, 900, 1 do
local Clone = BrickC:Clone()
Clone.CFrame = depositCFrame
Clone.Parent = ClientBricksWSFolder
ClientBrickCReserve[#ClientBrickCReserve+1] = Clone
end
for counter = 1, 900, 1 do
local Clone = BrickD:Clone()
Clone.CFrame = depositCFrame
Clone.Parent = ClientBricksWSFolder
ClientBrickDReserve[#ClientBrickDReserve+1] = Clone
end
for counter = 1, 900, 1 do
local Clone = BrickE:Clone()
Clone.CFrame = depositCFrame
Clone.Parent = ClientBricksWSFolder
ClientBrickEReserve[#ClientBrickEReserve+1] = Clone
end
end
registerBrickReserves()
local function findIndex(table, value)
for index, valueB in table do
if value == valueB then
return index
end
end
end
local function getFreeBrickOfType(Type: string)
if Type == "A" then
for _, Brick in ClientBrickAReserve do
if Brick.CFrame.Position == depositCFrame.Position then
return Brick
end
end
elseif Type == "B" then
for _, Brick in ClientBrickBReserve do
--print(Brick.CFrame.Position)
if Brick.CFrame.Position == depositCFrame.Position then
return Brick
end
end
elseif Type == "C" then
for _, Brick in ClientBrickCReserve do
if Brick.CFrame.Position == depositCFrame.Position then
return Brick
end
end
elseif Type == "D" then
for _, Brick in ClientBrickDReserve do
if Brick.CFrame.Position == depositCFrame.Position then
return Brick
end
end
elseif Type == "E" then
for _, Brick in ClientBrickEReserve do
if Brick.CFrame.Position == depositCFrame.Position then
return Brick
end
end
end
end
-- Get a random character
local function showBrick(Brick: Instance)
if not Brick:IsA("CFrameValue") then return end
if Brick == nil then return end
local Identifier = random(0, 1000000000)
ServerBricksTable[Identifier] = Brick
local BrickType = string.gsub(Brick.Name, "Brick", "")
local ClientBrick = getFreeBrickOfType(BrickType)
ClientBrickTable[Identifier] = ClientBrick
ClientBrick.CFrame = Brick.Value
animateBrick(ClientBrick)
end
-- Removing Bricks --
local function RemoveBrick(Brick: Instance)
if not Brick:IsA("CFrameValue") then return end
local Identifier = findIndex(ServerBricksTable, Brick)
destroy(ClientBrickTable[Identifier])
ClientBrickTable[Identifier] = nil
ServerBricksTable[Identifier] = nil
end
-- Handling the connection --
local Connection = BricksFolder.DescendantAdded:Connect(showBrick)
local Connection2 = BricksFolder.DescendantRemoving:Connect(RemoveBrick)
while true do task.wait(2)
if Enabled.Value == true then
local PastConnection = Connection
local PastConnection2 = Connection2
Connection = BricksFolder.DescendantAdded:Connect(showBrick)
Connection2 = BricksFolder.DescendantRemoving:Connect(RemoveBrick)
PastConnection:Disconnect()
PastConnection2:Disconnect()
end
if Enabled.Value == false then
Connection:Disconnect()
Connection2:Disconnect()
for _, Brick in ClientBrickTable do
destroy(Brick)
Brick = nil
end
for _, Brick in ServerBricksTable do
destroy(Brick)
Brick = nil
end
ServerBricksTable = {}
ClientBrickTable = {}
end
end