Game optimization is the practice of tinkering with your game's design and code; further improving performance on other devices to improve the playability of your game.
Game optimization in Unity. Source: https://www.pluralsight.com/courses/game-optimization-techniques-unity-1467
When you look into the perspective of any player, and if you EVER decide to make a multi-platform game on Roblox, what is important and set in stone is that you need to make sure it can run on even the smoothest of devices: you can't say that a gaming computer will run the same framerate as a phone, they're entirely different devices with their own specifications.
As a result, games on Roblox need optimization to ensure that everyone gains an equal representation and hopefully has a smoother gameplay experience. In this first part, we will be discussing the multiple ways you can optimize parts and other objects in Roblox games to ensure the best performance.
A union is when you take a collection of parts and combine them to form one shape, which is why it's called a union: it's a combination of parts jammed together into one.
Let's take the example of a chair modeled on Roblox Studio. If you decide to make a chair, you need to build the following: four legs, one base, one backrest, and a seat to set the player in. That's seven parts, with additional details that number could increase even more. Especially since a chair can be repetitive in your game as a decoration, that's bad for gameplay performance.
By unioning all of the parts together though, you create one uniform part. The only issue is texturing, but you can make sure all of your parts are textured correctly before applying a union. This drastically saves performance on devices that can't perform rendering many parts at once.
You might also be thinking that models are a good idea: which they're not most of the time, sorry to disappoint you. Models are also render intensive on older and lower spec devices because they're just a collection of parts that aren't in a union, at least for most of the time. They're good to keep unions in a separate place, but if you're planning to use a model to hold parts, make sure you union chunks together to put them inside of the model.
This is another common issue on the Roblox platform with certain games. People simply leave parts and textures exposed in areas the player can't see, which hogs device resources and ultimately stops the player from enjoying a smooth framerate.
A simple way to characterize what a player can see and what they can't see is by using raytracers, or by using a region that follows the player around. From here you can set up the settings for how big or small this region, or the field of vision of the player is, so that way they can tweak the settings until it fits them well.
From there you can calculate the area where parts and details should spawn into the workspace.
This is a very complicated step, and so if you're not already familiar with regions or raytracing in Roblox, I would highly suggest learning about them more before tackling this step.
When messing around with unions and meshes, one of the most important steps is determining which collision fidelity to properly use on Roblox. Collision fidelity is a setting in the Roblox properties tab on unions and meshes, which determines the collision hitbox of a union or mesh; this is a very important step in determining the physics of an object.
There are 4 modes:
Default calculates the collision of a mesh with a rough estimation and disperses it accordingly, by which it uses multiple parts to detect the collision hitbox. Obviously, this is a no-no!
Default Collision Fidelity. Source: Roblox Developer Forum
Next is Box, which just puts a box around the collision zone. This is the best for performance, but there is better for both performance and realism.
Box Collision Fidelity. Source: Roblox Developer Forum
Then, Precise Convex Decomposition uses surface geometry to get the most realistic geometry; however since it's a ton of processing to turn the area on the mesh into a collision zone, this falls flat as another collision fidelity option for performance.
Precise Convex Decomposition Collision Fidelity. Source: Roblox Developer Forum
So, what is the best collision zone method? Hull is. Hull is like PCD and Default, but instead of favoring performance over realism, it kind of wraps around an object; in simple standards if favors all of the object's details and it also does it with minimal performance.
Hull Collision Fidelity. Source: Roblox Developer Forum
As a result, you should use HULL over any other mode of collision fidelity. If you're going for the most optimal performance, then I'd suggest using box.
Usually in your games, parts will be free floating and with physics unless you tick on a special property called "Anchored," which disables the physics of the object. In games that have parts that don't really need to be moved, you WANT anchored to be on so you can reduce the amount of physics processing in your games. It also frees up physics processing for more important usage in the long run.
It's a very simple step, so not much really has to be said here.
This is more of a scripting practice than a practice for your game models and design, but I felt like it would be a good idea to talk about it here because you'll be recycling parts from time to time.
If you know what :Destroy()
is, it's simple. What it does is that when you call it, it just sets the object's parent to nil
so that it's no longer discoverable in the workspace. While this is a simple way to get rid of objects, what's not good about it is that the function itself can cause a lot of unnecessary server lag, and since the parts, or other objects, aren't technically "gone," it just creates a more intensive simulation for lower end devices.
However, there is a better way, and that's using DebrisService
. You can call it like this in a script:
local Debris = game:GetService("DebrisService") -- lib is now available
What Debris does is that it's like a queue that you can schedule parts on to delete them entirely. In a sort of way, it's like a conveyer belt that works on a separate thread to delete parts on a sort of timed basis.
To add ITEMS for deletion to the service, you can use :AddItem()
.
local DebrisService = game:GetService("DebrisService")
local Part = Instance.new("Part")
Part.Parent = workspace
Debris:AddItem(Part, 2) -- takes two args, the item and the amount of time until deletion in seconds
So as a result, use Debris
over :Destroy()
to better improve server performance and client performance.
I don't really have much else to say here other than that: if you need to optimize your game further, these steps here could really help out when developing games on Roblox. After all, you don't want your game to not work.