In my last post, I went over how to “improve performance and set performance goals” — that post is incredibly outdated and full of terrible advice. Do not follow it
It was very vague and my knowledge as a scripter & programmer has improved a lot
This topic will list a bunch of useful things that have helped many projects I’ve worked on and I’ll split it into 2 parts: For Scripters & For Anyone!
Note: The information provided here is updated in response to feedback and suggestions! I have been getting busier so some information may become outdated!
For Anyone:
-
CanTouch, CanCollide & CanQuery
BaseParts (Parts, MeshParts, Unions, etc) have the .CanTouch property which when set to false along with .CanCollide will have a small performance improvement and can still be hit by Raycasts and Region3 queries (so it’s best to set both of those properties to false on objects that don’t need to calculate physics and won’t be interacted with).
CanQuery is another property that can be disabled for a small performance gain. To my knowledge, it’s pretty new. -
Lighting
If your game does not need the ShadowMap or Future technologies, by all means, don’t use them. Something as simple as using the Voxel lighting can make your game’s performance do a 180 in terms of lag! Rendering fewer shadows may also give your game small performance boosts (this may not produce noticeable gains and is not intended to be a performance-enhancing feature by Roblox); you can disable the .CastShadow property on BaseParts that you don’t want to cast shadows for that (potentially) small boost. [Lighting] -
Collision & Render Fidelity
Unions and MeshParts have this wonderful .CollisionFidelity property which when set tobox
will change the hitbox of the Union or MeshPart to a box! This means less work for the server or client! BaseParts and Meshparts have the .RenderFidelity property, which when set toperformance
will change how the Instance looks when at a longer distance from the player. -
Teleporting
With teleportation you can teleport your players between places and massively increase the size of your game by splitting the game up! If there’s less to load, there’s less to load! -
Useless Replication
If something shouldn’t be replicated (shown) to the client then don’t put it in places like ReplicatedStorage, put it in a place like ServerStorage. Anything the client can see must first be replicated to them, which takes valuable resources. (Edit: You can check out more information on that here.) -
ANCHOR
Make sure you anchor things that shouldn’t move! I’ve worked with developers who have front-page games who just “forget” to anchor parts (you know who you are)! This makes Roblox calculate more physics, thus, causing beautiful lag. -
Transparency
While small, it is worth noting that the .Transparency property exists! In Roblox’s own words (here) " Use partial objectTransparency
sparingly, as semi-transparent objects inhibit a lot of internal rendering optimizations. If you require transparency on severalBaseParts
, attempt to merge them using solid modeling (a transparent union is more optimal than a group of 10 smaller transparent parts)." -
Textures
Textures are amazing if you want more than Roblox’s materials but they come at a cost. You should use the built-in materials (and now the MaterialService) in favor of textures because textures occupy more memory than materials (GraphicsTexture
in the Developer Console underMemory
). If you want to use textures I don’t advise against it, especially since you can really solidify a game’s feeling with textures! -
Player Count
Stress test your game! See how well it performs with a bunch of players and reduce the MaxPlayers you can have in one server! -
Humanoids
As a lot of developers know: humanoids can be very laggy when there are a lot of them together. You can disable HumanoidStateTypes you won’t use but in my experience, it appears to make no difference. You can also just stop them from moving and calculating physics by anchoring and changing properties. I recommend just not having dozens of humanoids near each other! If you were willing you could even make enemies or NPCs that don’t rely on the humanoid (that’s my personal favorite). -
Content Streaming
Please read the official documentation here. They explain it way better than I could.
In-experience content streaming allows the Roblox engine to dynamically load and unload 3D content and related instances in regions of the world.
For Scripters:
-
Infinite Loops
Good ol’while true do
… I’m sure every scripter knows not to have tons of these. If you do, try using .Changed, :GetPropertyChangedSignal or parts of the RunService! Try not to use infinite loops where they aren’t needed! -
FindFirstChild
Roblox says it best:
I’m not discouraging the use of FindFirstChild, I’m discouraging the use of FindFirstChild where it isn’t needed -
Wait()
Usetask.wait()
instead ofwait()
. This is explained later in the post. -
Instance.new()
UsingInstance.new("Instance", setParent)
and setting the parent with the second parameter is actually slower than instancing then setting the parent on another line, likelocal instance = Instance.new("Whatever")
and theninstance.Parent = whatever
Source -
Connections
(See Roblox’s Handling Events)
This one might be rushed until I can refine it but here’s the basics: You can use theConnect()
function to “connect” events to a function, you probably do this a lot already but might never useDisconnect()
. The link listed above will go in more depth but do note that usingDestroy()
on a script or an ancestor of a script will disconnect all connections and you may not need to disconnect functions if a script will soon be removed this way. You can also useOnce()
instead ofConnect()
, this disconnects after the event is fired! -
_G & Global Variables
This post explains _G the best and reinforces the idea that _G is not slower than module scripts. A lot of scripters call _G bad practice when it’s just how you use it. If you’re storing everything in _G then yes, it’s bad practice. Using it in general is not bad and it’s down to preference and organization. -
Repeating Expensive Calculations
Don’t repeat expensive calculations (if you don’t need to)! Store the results of something like:GetChildren()
in a variable when possible.
An example is in one of my games. I wanted to give every player a point if they’ve completed a task during a specific trigger or remove points if they failed, and slowly increase points lost the further in the game they were.
-- Bad Example
for index, player: Player in ipairs(Players:GetPlayers()) do
local losePoints = 5 -- Stores the points they should lose in the loop (BAD)
if round >= 50 -- If these were a lot of expensive calculations it would be laggy
losePoints = 25 -- Because it runs once for each player in the game
elseif round >= 20 then
losePoints = 20
elseif round >= 15 then
losePoints = 10
end
if isTask1Complete or isTask2Complete then
points.Value += 5
else
points.Value -= losePoints
end
end
-- Good Example
local losePoints = 5 -- Stores the points they should lose OUTSIDE the loop instead!
if round >= 50 then -- If these were a lot of expensive calculations it would perform better!
losePoints = 25
elseif round >= 20 then -- (Yes I know I shouldn't compare each round in a series of elseif statements if I'm worried about scalability, I quickly wrote this up as an example)
losePoints = 20
elseif round >= 15 then
losePoints = 10
end
for index, player: Player in ipairs(Players:GetPlayers()) do -- Tidy loop
if isTask1Complete or isTask2Complete then
points.Value += 5
else
points.Value -= losePoints
end
end
Hey! The task library has great alternatives to wait()
and spawn()
!
task.wait()
is the same as RunService.Heartbeat:wait()
but takes less time to write and with just task.wait()
is safe!
FUN FACT
Scripters! You can use operators like +=
and -=
instead of x = x + whatever
When I learned this it saved me so much time!
You can also use FindFirstChild(“Name”, true) to loop through descendants (looping through a bunch of objects will have a delay)
I whipped this topic up in just a few hours of research and will likely be adding more to it in the future. If you have any suggestions please suggest them!