Introduction
This post is intended to be a resource to provide valuable information on performance considerations when developing games/projects. To those who may come across this thread, if there are concerns of inaccurate information please contact me.
General
Introduction To General Performance Considerations
The general category will include general performance issues that are affected across other development categories.
Particles
Introduction To Particles
Particles are powerful tools that we can use in order to improve the quality of our games. Particles are automatically optimized (based on graphics level) by Roblox if they happened to be enabled in the workspace
. However, there is a a method to ParticleEmitters
known as :Emit()
. You can read about this here.
As mentioned on the DeveloperHub:
TLDR; :Emit()
ignores the automatic optimisation Roblox offers. One method of commonly practice is to have a module for emitting particles based on the local player’s quality. An example is shown below:
return function(Particle, EmissionAmount)
local QualityLevel = UserSettings().GameSettings.SavedQualityLevel
if QualityLevel == Enum.SavedQualitySetting.Automatic then
Particle:Emit(EmissionAmount)
else
local Compressor = QualityLevel.Value/10
Particle:Emit(EmissionAmount*Compressor)
end
end
You can use this function by copy and pasting it into a ModuleScript
. An example of the use case is shown below:
local Emit = require(Emit)
Emit(Particle, Amount)
The last notable thing on particles is to obviously avoid extremely high rates if possible. Increasing the rates on ParticleEmitters
will hit performance quite notably on a lower-end device. Simply ask yourself if you really need that many particles.
Instance Count
Introduction To Instance Count
Though this is pretty self-explanatory I believe this topic is still worth discussing. It should be common sense that the less objects and instances you have in your world, the better it’ll be overall. That being said, there are times where reducing the amount of instances become impossible while keeping quality in mind. However, there are many methods you can apply depending on your scenario.
To those who have trouble with reducing instances with blocks (if you’re making a square based block game) you may find greedy meshing as an applicable scenario to your project, take a look at this.
Another example is datastores. I commonly see many beginners fall into the trap of converting a whole table into instances. using Folder
as the table and StringValue
, NumberValue
, BoolValue
to represent the values. Some data you simply don’t need displayed. A player may end up having 200+ instances just to represent data when a RemoteFunction could be used to retrieve the data. Some creation of instances is convenient (which is fine) but trying to create a whole list isn’t necessary.
There is another method that may help which is to let’s say compact your inventory that may look like this:
local inventory = {
{id = "apple", quantity = 3},
{id = "orange", quantity = 4},
}
into a compacted string like so:
local inventory = "id:apple,quantity:3;id:orange,quantity:4"
If you were to create instances of both, one would just require a StringValue
object and the other would require:
Inventory (Folder):
→ 1 (Folder):
—> id (StringValue)
—> quantity (NumberValue)
→ 2 (Folder):
—> id (StringValue)
—> quantity (NumberValue)
7 instances. (The downside of the other one would be reading it and accessing the data from the server).
Using Multiple Places
Introduction To Having Multiple Places
Having multiple “Places” is extremely ideal for a heavy content game. While it may take a fair amount of work, with good organisation and with the help of Roblox Packages. You can easily reduce the amount of instances/maps/meshes and running scripts in your world.
If you happen to be a programmer, one thing to look forward to is TeleportService.
Taking advantage of multiple places is something everyone should definitely consider pre-development as it can be a huge game-changer.
Lighting
Introduction To Lighting
Lighting is more important than it seems and can drastically affect the performance of lower end users. The most expensive technologies are ShadowMap
and Future
because of how much more detailed they are and the more functionality it provides. Generally, just keep in mind that the lighting you choose does matter.
Memory
Introduction To Memory
Memory is important when it comes to developing your game. You usually want your game to be accessible to every platform allowing you to maintain the highest player base possible. If your game doesn’t support mobile/console then perhaps this may not be as relevant but do note that even lower end laptops/pcs can still be affected.
What is memory?
Memory is the amount of data needed to be stored for unique assets. These are a few assets that use up memory:
- meshes
- textures
- animations
- sounds
- unions (CSG)
Scripts also use memory, and scripts can cause memory leaks (which is basically the equivalent of cancer to a game). Memory leaks can be avoided through good coding practices. Finding memory leaks is usually a very difficult and tedious task.
What should my memory be at?
This is a common question asked quite frequently and that is how much memory should your game shoot for. Here is an image of the estimated memory storage available on each device:
You can find a post on it here.
One thing you can do is look at the front-page games of Roblox and check out how they are doing on memory. You can check memory by joining a game and pressing F9. I’d recommend looking at games that are similar to yours (if they exist).
How can I reduce memory?
Because memory is such a broad topic, I’m going to list what I know of here. I want to point out that not everything I know can be backed up with evidence. I will be labelling what I know works and am unsure about. will represent unsure, will mean that there is evidence to support it. If I made a mistake or you know if displayed information is wrong, feel free to contact me to correct it.
Methods | Factual |
---|---|
Reducing Image Dimensions | |
Compressing Image Size | |
Reduce Amount Of Unique Images | |
Reduce Amount Of Unique Animations | |
Reduce Amount Of Unique Textures | |
Reduce Amount Of Unique Decals | |
Reduce Amount Of Unique Meshes | |
Reduce Amount Of Unique Unions | |
Reduce Amount Of Sound Assets | |
Not Caching Variables And Functions In Scripts | |
Storing Assets In Server Storage Rather Than ReplicatedStorage | (Reduces Client Memory) |
Some of these are unavoidable. For example, functions and variables are extremely useful and makes things much easier while other methods such as meshes and images can possibly be reused. This is only here to provide information.
One last thing to note is for ModuleScripts
. I believe that while you can not reduce the “total memory” of all the module scripts being required, you can require a module when you need it so that the memory eventually reaches the maximum rather than starting off with the max. This is a optimisation I’ve heard some developers may use.
Replies To Consider
Scripting
Introduction To Scripting Performance Considerations
Scripting is a huge part of game-development and overall there a lot of things you can do to optimise and improve performance of your projects. A lot of times, scripts are also the reason your game may have lag or remote latency. Algorithms and methods are sometimes applicable to make some impact changes.
Luau
Introduction to Luau
Luau, is an extension of Lua created by Roblox. Features from Luau proves to be much more performance beneficial over Lua. Luau is constantly being updated with new features such as a recent new feature implemented into the table library table.clear()
which are much more optimized compared to clearing tables manually or making a new one. On the platform, it is recommended to use Luau, however, some of us may not be happy with it and may just stick towards official Lua/RLua more.
Loops
Introduction to Loops
Some individuals may like to compare the speed of loops. While I highly doubt it’s the reason your game is lagging, I still believe it’s worth noting as if you are looping through large lists/dictionaries it could make a potential impact (while unlikely). Here’s a post that is really an eye opener:
Don’t use ‘next’ instead of ‘pairs’ | by Stephen | Medium
RemoteEvents/RemoteFunctions
Introduction to RemoteEvents and RemoteFunctions
Remote events and remote functions are necessary for a game to establish a connection between the server and client. However, I’ve noticed in one of my projects, sending large amounts of data as an argument will simulate something similar to a bad-wifi/latency lag. I want to warn everyone that it’s always better to just keep the amount of information you send between the server and client as minimal as possible (I was sending giant tables).
Does the amount of RemoteEvents/RemoteFunctions matter?
I’ve come across this question several times. RemoteEvents do in fact have limitations. They have a data-size limitation as well as a rate limitation. Here are some posts that justify that.
RemoteEvent Rate:
Limits of RemoteEvents - Help and Feedback / Scripting Support - Developer Forum | Roblox
And a notable comment:
So, what does this mean? Well you could use one remote event / remote function for everything but sometimes it’s better to keep things separate for better readability and organisation. So, what’s the best option? Well:
Visual Effects
Introduction To Scripting Visual Effects
Throughout my experience communicating with other developers, I’ve noticed one thing I believe everyone should understand. The server should be running at maximum efficiency processing and handling important data and information. This means that majority of visual effects should be done on the client and replicated across the clients if necessary. The benefits of this is not only better performance on the server but smoother visuals on the client.
I’ve seen far too many people tween/lerp meshes/models on the server or spawn particles on the server when they could just replicate the effects onto a singular client or many using a RemoteEvent
and the :FireAllClients()
or :FireClient()
method.
Algorithms
Introduction To Algorithms
There are ton of Algorithms. Not every single one may be applicable to you. Algorithms are different ways to approach certain situations to improve efficiency of code. You can read more about it here. For a more friendlier article you can read this.
While algorithms are extremely helpful, they aren’t universally applicable, certain algorithm can only be used under specific situations. For example, binary search is a well known searching algorithm, however, it can only be applied on sorted lists/arrays. Depending on the situations, algorithms may be the game changer in performance, in other times, perhaps you don’t need them.
Bad Practices
Introduction To Bad Scripting Practices
When it comes to scripting, bad practices are considered from typos to code structure. While some bad practices may just be a personal preference. Some may have a minor to major impact in your project. There are many code smells and bad practices I could list, however for the purpose of this post, I will mention a few that have direct impact on performance.
I must also say, there are plenty of posts out there and one I find very informative is this one:
https://devforum.roblox.com/t/what-are-bad-programming-habits-that-you-see-often-by-scripters/761033
Bad Practices:
Using The Second Argument Of Instance.new()
Using The Second Argument Of Instance.new()
There was a public PSA on this topic here.
TLDR: Parent last after setting all the attributes/properties. The reason for this is so that the server does not need to replicate all the changes to the client. It’d be preferred if all the properties were set and then parented so it’s all replicated at once. For more information read the PSA.
Using Loops Improperly
Using Loops Improperly
Loops are extremely helpful and they are capable of helping us in many ways. But one way that I’ve seen many using loops improperly is using loops over built in RBLX events. Some built in events may have specific triggers that avoids using loops that can greatly help and other times are much more optimised.
An example would be: using a infinite loop (while loop) to update a TextLabel. Instead use .Changed
or :GetPropertyChangedSignal
.
You’ll quickly notice that unnecessary looping can cause game crashes with enough of them. Don’t be scared to use Roblox events as they have been created for a purpose.
Not Localizing Variables
Localizing
Localizing is mostly minor. There is a difference but not that big of a difference. There are definitely other things you could prioritise over. Here’s an example:
local Clock = os.clock
local Start = Clock()
local RunService = game:GetService("RunService")
local VarToEdit
for i = 1, 1000 do
VarToEdit = os.clock() -- this does not use our cached variable
end
print(Clock() - Start)
Start = Clock()
for i = 1, 1000 do
VarToEdit = Clock() -- This one does
end
print(Clock() - Start)
And here are your results:
You’ll notice by a very small amount, that using the cached variable is faster. But this doesn’t mean you should change everything in your game. It’s just something to know and trust me, if your game is lagging, it’s not because you didn’t localise your functions.
I do want to mention that recent changes to Luau has already localized the libraries. You can read about changes here and here. That being said, if you wish to stick closer to official lua you can still cache libraries as practice.
Not Caching Your Variables As A Local Variable
Not Caching Your Variables As A Local Variable
As mentioned earlier, the more functionality you give to something, the more expensive it usually is.
Memory Leaks
Introduction To Memory Leaks
Memory leaks, the cancer of a game. Memory leaks are caused by scripts that are not cleaning up / removing instances/assets that were created and is no longer being used. Memory leaks are also caused by internal code (usually RBXSignals that don’t get disconnected when finished with). There are 2 posts that explain really well on this topic here and here.
The easiest way to prevent memory leaks is to ensure that you are destroying instances and disconnecting your connections. If you are constantly creating things but never destroy them the game will slow down and eventually crash.
One useful tool to new developers is to use the maid class created by Quenty. You can find it here.
Building
Introduction To Building Performance Considerations
When people first start building, usually they don’t consider optimisation as their priority.
There a few things that should be mentioned in this topic so I’ll go ahead and break this into categories.
Textures And Decals
Introduction To Textures and Decals
If you haven’t read the section on Memory in General, I suggest you do. Using multiple unique textures and decals is one way to increase memory in your world. That being said, certain built-in materials render easier than others (look at BasePart Properties).
Part/Texture Count
Introduction To Part/Texture Count
If you haven’t checked out General > Instance Count then I suggest you read that section first.
Moving on, in my personal experience, Building has been one of the most guilty in overusing objects/instances. As mentioned in the section of Instance Count, there are ways to reduce part count through a method known as Greedy Meshing. Unfortunately, greedy meshing isn’t applicable in every situation so the best tip for you builders is be aware on how many parts you are using and look for anything you can combine.
That being said, BaseParts are not the only thing that are overused. If you must use Textures try to use textures on faces that matter. If a face of a Part will never be seen by a person, don’t add a texture on that face.
Here is a nice visual example from Mariofly5’s post:
Mariofly5 has also made a post on building optimization which you can read about here.
Level Of Detail Property
Introduction To Level Of Detail
Level Of Detail is a property of Models
that was recently introduced which works with the property called StreamingEnabled
in Workspace
. For more information, check out this post.
In short, Level Of Detail will help with the system knowing what to render out and what to keep. Having the property on Automatic
or Disabled
can benefit lower end devices.
BasePart Properties
Introduction To BasePart Properties
When you build a map, you need to consider if certain parts need collision or not. The reason for this is because Roblox performs physic calculations on parts with specific properties. The best properties to have for builds would be:
Property | Value |
---|---|
Anchored | |
Material | SmoothPlastic |
CollisionFidelity | Box |
CastShadow | |
CanCollide | |
Transparency | 0 or 1 |
These would be the ideal properties to have in every BasePart. If you’re making a simulator and detail isn’t required consider turning off CastShadow
and changing the CollisionFidelity
to box. In most cases, unless you really need Roblox’s physic calculations on your BasePart, Anchored
should always be set to true.
As for transparency, here’s a quote from colbert2677
from here
BasePart Material
If you’ve played games on Roblox, you may have seen certain games provide an option for lower end devices which basically changes all the material to SmoothPlastic and removes textures. Now, this is true that SmoothPlastic is much better as a material for performance. Materials such as Neon
and ForceField
will tend to be much more expensive. ForceField has extra functionality such as adding a texture to have a “ForceField” affect while Neon just has extra glow.
If you plan offering a lower graphics option to players, consider doing the following:
- Change the lighting to something less expensive locally
- Change all materials to SmoothPlastic locally
- Disable CastShadow for all BaseParts
Meshing and CSGs
Introduction To Meshing Performance Considerations
Since I’m not a modeler, I don’t know much about performance considerations on this topic. I’ve done some research and well meshing comes down to a few things. The post I used for research can be found here and is much more informative.
Triangles
Introduction To Triangles
Every BasePart
in Roblox has geometry to it and are conformed by triangles. Meshes and unions tend to have more triangles because of the more complex shape compared to Roblox parts. The less triangles you have the better.
Here’s a quote from here.
RenderFidelity Property
Introduction To RenderFidelity Property
If you haven’t checked out LevelOfDetail
property in the Building
category for models, I suggest you take a quick look at that.
RenderFidelity
is similar to LevelOfDetail
except it doesn’t require StreamingEnabled
. Instead of completely removing the Model, instead, it’ll drop in quality. This can be very beneficial to players with lower end devices. Setting your RenderFidelity
to Automatic
would be the best option for performance.
Collisions
Introduction To Collisions
I’ve already mentioned collisions in Building > BasePart Properties. Meshes and CSG’s are considered BaseParts so please refer to BasePart Properties in building.
LowPoly Vs HighPoly
Introduction To Lowpoly vs Highpoly
You’e probably heard of the term of Low Poly and High Poly before. What does it mean and how does this affect your world? Well, rather than explaining I’ve found a very informative article here that you can read about. Generally, simulators sticks to “Low Poly” because of how simple it looks as well as the best choice when creating a game across all platforms (Mobile, Console, PC) because of the performance benefits.
Animations
Introduction To Animation Performance Considerations
After some researching, I was unable to find anything that really should be considered for animations. We can probably assume the more unique animations there are along with the more keyframes each animation has the more memory it will consume.
My suggestion would be don’t bother with animations that much. If your game is lagging it’s likely not due to animations.
Gui
Introduction To GraphicalUserInterface (GUI) Performance Considerations
After researching upon this topic, I’ve found a few things that you should consider looking at to optimize your user interface.
GUI Visibility
Introduction To GUI Visibility
One common thing people do is like to tween their GUI. Usually, when people animate their UI, they animate it off the screen to hide it. While this accomplishes what the programmer wants, if they do not hide the user interface with the Visible
property, it’s still being rendered.
So how does toggling the visibility of a GUI help? Well, you may have noticed already but turning the visibility of a GUI off means that you are disabling functionality of the user interface. This means clicking, hovering and all that neat stuff gets disabled as well.
You can read more about GuiObject here, the article talks about other benefits to toggling the visibility such as disabling rendering for that time and etc.
Static GUI
Introduction To Static Graphical User Interface
Static GuiObjects will reduce rendering calculations which will in return benefit you.
Replies To Consider
You can find more information here.
ViewportFrames
Introduction To ViewportFrames
ViewportFrames were recently introduced Roblox allowing 3D objects to be rendered onto a 2D screen. ViewportFrames are now very popular among games and are a extremely powerful tool. That being said, you should consider how expensive it is rendering a 3D object onto a screen.
This isn’t the end though, recently WorldModel
’s were introduced allowing physic calculations to be done in the GUI. This allowed animations to be played and rendered as well as adding other functionality to the ViewportFrame. While this is awesome you should limit the amount of WorldModel
’s used since these are very expensive.
One tip I’d recommend is reusing camera instances of the same viewport object if possible. Having just a static model is preferred for a viewportframe.
UICorners
Introduction To UICorners
Like Viewportframes, UICorners are relatively new and come in very handy. Obviously, with this new tool, there are downsides. Roblox has listed the pros and cons which I will quote here:
So when should you use UICorner? Well, if you’re simply trying to make frames with smooth corners I suggest using 9-Slice. For cases where this is unavoidable (for example, needing to curve a ViewportFrame or ImageLabel’s Corner) you should use UICorner
’s.
Resources And References
Scripting
Don’t use ‘next’ instead of ‘pairs’ | by Stephen | Medium
Garbage Collection and Memory Leaks in Roblox - What you should know
PSA: Connections can memory leak Instances!
https://devforum.roblox.com/t/what-are-bad-programming-habits-that-you-see-often-by-scripters/761033
https://devforum.roblox.com/t/localizing-variables-but-not-functions/369038
How to use a Maid class on Roblox to manage state
Consume everything - how greedy meshing works
Algorithm efficiency and alternatives to table.find
PSA: Don't use Instance.new() with parent argument
Part Pooling - Increase performance with many parts
PartCache, for all your quick part-creation needs
GUI
Static UI Performance Improvements
Meshing
Differences between High Poly Vs Low Poly 3D models | by Arjun Patel | Medium
Levels of Detail for Mesh Parts
Quick Guide Into CSG: Increasing Performance of Unions & Meshes
Introducing Level of Detail for CSG Parts
Building
Introducing Level of Detail for CSG Parts
Building Optimisation | Tips and tricks!
BasePart | Documentation - Roblox Creator Hub
Credits
Contributors: @Mystifine // @EDmaster24 // @colbert2677 // @DragRacer31
Feel free to contact me with more information I can add onto this post.
Last Update: 2023-08-12T04:00:00Z