Performance considerations, improvements, and optimizations when making a game

Introduction


This post is intended to be a resource to provide valuable information on performance considerations when constructing games. 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 fantastic tools that we can use in order to improve the quality of our games. Particles are automatically optimized (based on graphics level) by Roblox but there is a way of using them through the method known as :Emit(). You can read about this here.

As mentioned on the DeveloperHub:

Now if you’re creating special effects that require you to use the :Emit() function, I’ve created a function that compresses the amount of particles based on the local players graphic levels.

return function(Particle, EmissionAmount)
	local QualityLevel = UserSettings().GameSettings.SavedQualityLevel
	if QualityLevel == Enum.SavedQualitySetting.Automatic then
		local Compressor = 1/2
		Particle:Emit(EmissionAmount*Compressor)
	else
		local Compressor = QualityLevel.Value/21
		Particle:Emit(EmissionAmount*Compressor)
	end
end

You can utilize this function by copy and pasting it into a ModuleScript. You can then simply require the module script and do the followig:

local Emit = require(Emit)
Emit(Particle, Amount)
Instance Count

Introduction To Instance Count

Though this is pretty self-explanatory I believe I should still talk about this topic. It should be common sense that the less objects and items you have in your world, the better performing it will be. That being said, there are times where reducing the amount of instances become impossible while keeping quality in mind.

To those who have trouble with reducing instances with blocks (if you’re making a block game) there are a few posts that can help you like this one.

Overall, be aware of how many instances you are using and ask yourself; is it’s necessary? This doesn’t only apply to building, as an example, some programmers strictly stick to using Table overs objects to store values while others find it convenient to use objects. Read the other categories to learn more about this.

Using Multiple Places

Introduction To Having Multiple Places

Are you making a game with a LOT of content? If that is the case, you may want to consider using multiple places within the same Universe. By creating multiple places, you can split up worlds/dimensions as well cut down on scripts that may be crucial only to certain worlds.

You can learn about how to use TeleportService and start using multiple places. Examples of games that may need to use multiple places are MMORPG grinding games.

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. You can see more about this in the Building Category which talks about CastShadow.

Memory

Introduction To Memory

Memory is important when it comes to constructing your game. You usually want your game to be accessible to every platform to acquire the most amount of players as possible. Now, some of you may not care about mobile support and if that’s the case memory isn’t as important (but memory leaks are when it comes to scripting). Regardless, you still want to optimize your game as much as possible to provide the best experience to players.


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)

Please note, memory is measured by unique assets when it comes to visuals not the amount. By now, it should be common sense to reduce the total amount of items (instances) in your world if possible.


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 more popular games as they may possibly have mobile support.


How can I reduce memory?

Because memory is such a broad topic, I’m going to list majority of everything here. Please note, some information is rumored and not 100% accurate. I’m going to be labeling what I know is for sure factual.
:heavy_minus_sign: will represent unsure, :white_check_mark: will mean it’s factual. If I made a mistake or you know if one is factual or not feel free to contact me to correct it.

Methods Factual
Reducing Image Dimensions :white_check_mark:
Compressing Image Size :heavy_minus_sign:
Reduce Amount Of Unique Images :white_check_mark:
Reduce Amount Of Unique Animations :white_check_mark:
Reduce Amount Of Unique Textures :white_check_mark:
Reduce Amount Of Unique Decals :white_check_mark:
Reduce Amount Of Unique Meshes :white_check_mark:
Reduce Amount Of Unique Unions :heavy_minus_sign:
Reduce Amount Of Sound Assets :white_check_mark:
Not Caching Variables And Functions In Scripts :white_check_mark:
Lower Amount The Amount Of Modules :heavy_minus_sign:
Storing Assets In Server Storage Rather Than ReplicatedStorage :white_check_mark: (Reduces Client Memory)

Please note, 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.


Replies To Consider


Scripting

Introduction To Scripting Performance Considerations

When it comes to scripting, we need to think logically. For a script to perform at it’s best, ideally you want to limit the amount of tasks for the script to execute. This is where algorithms come in to improve efficiency of code.

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 more.

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 handling important data and information. This means that all 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 on the server or spawn particles on the server. To replicate visuals across all the clients, consider looking at RemoteEvents and their :FireAllClients() method.

Algorithms

Introduction To Algorithms

While I could talk about Algorithms there are plenty of articles and posts online that can help you understand. In short, 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 algorithm, however, it can only be applied on sorted lists/arrays. Depending on the situation, algorithms may or may not be applicable.

Bad Practices

Introduction To Bad Scripting Practices

When it comes to scripting, bad practices are considered from typos to code structure. Though some are not necessary to change (if it’s personal preference), but some may become more crucial as we move to code structure as it can directly affect game performance. When it comes to bad coding practices, this can be extremely broad so I’ll list as many common examples as possible. Let me know if I’ve missed some important ones. For the purpose of this post, I will only post bad practices that affect 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. If you’re lazy and don’t want to click links, to keep it short it’s best practice to parent last. 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 connections. Built in connections are loops but they are much more optimized. An example would be: using a infinite loop to update a TextLabel is not recommended, instead use .Changed or :GetPropertyChangedSignal.

You’ll notice that after adding a few loops to just update TextLabels you’ll end up crashing your game at one point.

Not Localizing Variables

Not Localizing Variables

Not Localizing variables are sometimes important for performance. This is evident when running functions that have reiterations (loops).

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.

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 functions you give to something, the more expensive it usually is. This is why when constructing let’s say an NPC system for an example, the dumber it is the better. By localizing, you limit the variables to the script it’s in.


Memory Leaks

Introduction To Memory Leaks

Memory leaks are caused by scripts that are not cleaning up / removing assets that were created and is no longer being used. Memory leaks are also caused by internal code (usually loops or 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 and disconnecting your connections and object. If you are constantly creating things but never destroy them of course the game is going to crash at one point.

One useful tool to new developers is to use the maid class created by Quenty. You can find it here.

Techniques And Methods

Introduction to Scripting Techniques And Methods

On the platform of Roblox, developers are constantly looking for new ways to approach things in order to improve performance. I’m going to be listing a few interested topics here that you may want to look into!

PartCaching / PartPooling

Introduction to PartCaching and PartPooling

PartCaching/PartPooling is caching and reusing parts to avoid creating new ones. There are 2 posts I’ve found on this topic that provide premade modules and more information here and here.


Building

Introduction To Building Performance Considerations

When people first start building, usually they don’t consider optimization as their priority. If you’re trying to make a popular game that supports all platforms then this may come to mind.

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:
image

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 :white_check_mark:
CollisionFidelity Box
CastShadow :heavy_minus_sign:
CanCollide :heavy_minus_sign:
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. Anything that has more functionality would be more expensive.

If you plan offering a lower graphics option to players, consider doing the following:

  1. Change the lighting to something less expensive locally
  2. Change all materials to SmoothPlastic locally
  3. Disable CastShadow for all BaseParts
Tips

Introduction Tips

Here are a few great tips I’ve found that have it explained better than I could so. Some of these may apply to other categories such as CSG’s and Meshing.


Source


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 or having performance issues it’s more likely it’s another cause.


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. This is good because it accomplishes what they want, BUT they usually do not toggle the visibility of the GUI.

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 GUI. As we know, the less functionality the better.

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 2D 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.

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

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


Credits

Contributors: @Mystifine // @EDmaster24 // @colbert2677 // @DragRacer31

Feel free to contact me with more information I can add onto this post.


Last Update: 2020-10-13T04:00:00Z

155 Likes

I feel like these resources are really useful.
Meshing and Animations are blank, though.
I’m guessing you’ll fill them later.

3 Likes

Thanks, dude. I’ve always looked for ways to increase performance. This is so helpful.

3 Likes

No problem, I’ll be updating this post as I gather more information. You may have noticed meshing and animations are blank. I’ll be filling those out sooner or later.

EDIT: I’ve just gone through the whole post again and made adjustments and added a few topics such as UICorner.

3 Likes

This is more than enough for me lol. I’m just glad I can figure out optimizations now.

1 Like

This is actually the limit to how much memory that device can use, not a recommended amount.

1 Like

Thank for letting me know, I’ll go make changes. I believe it’s a estimated value:

1 Like

This is a nice collection of research available. Unfortunately won’t do much with the whole issue of people not doing their own searching, but still helpful for those who pay attention to the Resources category at the very least.

So comments time.


General - Particle Count

This variable isn’t used. Additionally, the maximum in game quality level is 10. I don’t know why Studio chooses to differ and mark it up to 21 though.

Enums have a value, use that instead of the name. All quality levels have a value equivalent to the actual quality level they’re running at, with automatic having a value of 0 (unfortunately that means you can’t determine much about automatic, including how it’s currently configuring graphics).

-- That division by 10 is where you were supposed to use MaximumQualityLevel.
local Compressor = QualtiyLevel.Value/10

It’s good to do this in practice (glad my boy Emit has some love, I don’t see it used that often especially in places where it matters) but using Emit may not be practical in all cases. Emit will instantly emit n amount of particles at one time and that may not be desirable in all cases where you want to do trailing or let particles off via Enabled. Use with discretion.


General - Memory

Another important missed consideration, although your list probably wasn’t exhaustive, is sound. Sound is a huge consumer of memory enough to warrant a presence on the thread.

Developers often find it easier to store sounds in storage services, especially music, however sound is capable of consuming a lot of memory especially for longer, powerful music. You can clear off a few tens of memory usage by not placing sounds in the DataModel. Sounds may be fine but music is a huge consideration, especially if you have a lot of it.

Sounds can stay if you find that creating and removing them is expensive or causes delays, however for music best practice is to not load it in until you’re sure you need it for a certain duration. You can get rid of it once it’s no longer needed to clear up some memory.


Building - Textures and Decals

I actually want to counter this and say don’t. Materials are equally, if not more expensive, than custom textures and you have less control (for example, being able to display the texture across only faces that are possibly visible to the player).

If performance is big on your mind and takes precedence over aesthetic, disabling all materials (using SmoothPlastic) is significantly more beneficial for performance. There is a reason why games with settings features are often featuring “disable materials” as a setting.

I see you covered that in BasePart Material though, which is good. It’s just that the information is sprawled out when it should be joined or available all at once.


Gui - Missed point

Something that was missed that would be good to touch on is the fact that static Guis are less expensive to draw than dynamic Guis. That meaning, it’s quicker to draw Guis every frame that don’t change than it is to redraw them.

So for all the folks out there who like tween-vomit for their Guis, just know that any spikes in Gui draw time (they’ll be visible on the MicroProfiler, not too much to the player circumstance depending) are probably coming from the fact that there’s a lot of tweens operating. A game doesn’t need tweens everywhere to look good (a sentiment I wish my own team shared).

Citation:


's all.

6 Likes

What about voxel usage for terrain? Is there any documentation on stats for that?

Oops! That is my mistake. Thank you for pointing that out. I was going to use that value but it seems like I’ve forgotten to do so.

I forgot QuaalityLevel.Value returns a number.

This is a whole other category I missed. I completely forgot about sounds. Thank you for mentioning that.

Would it be fine If I made edits to my post using your new information?

Unfortunately, I’ve never worked with terrain before. I’ll see what I can find and I’ll make edits if I find anything.

1 Like

Feel free to do so. The feedback was there to help you improve your post or prompt a discussion if the information I had wasn’t correct and could be countered with a citation.

3 Likes

how do i stop the loop and like resume it do i just
if loopneeded then
–loop
else
–loopnot
end
or is there smthg else

You can have a variable:

local Loop = false;
if LoopNeeded then
   Loop = true;
   while Loop do
      -- loop here
   end
else
  Loop = false; -- should break the loop
end
1 Like