All about optimization

Hi, i’m making this tutorial, because i wan’t to show you few things about optimizing your game. I had a lot of problems like this, and it was my faulth, soo maybe you’ll not repeat my mistakes. Let’s begin:

1. Do i really need it?
Soo, this question is first thing you should do, why?

We have a lot of ideas and with time we change them, soo if you really don’t need it already, don’t touch it. For example we have fighting game where you wan’t to add shop, but first you need to make weapons to buy. When you made weapons you think: “buying weapons is not interesting, let’s make them drop from bosses!” - then when you’ve made shop, you have to delete it or disable it. This is where planning comes handy!
you can make things like data stores or usefull functions at the beginning, because it always needed in most games.
2. Plan your game, especially when you making it with friends
Before optimizing aspects, remember to plan your game, i know this is hard, but it will help you organise things and make work easier.
If you or your friend makes meshes or models, tell him to use optimization tips from below, it will help your game with really small affort

A) Models

1. Shadows will not be necessary!
especially for low - mid poly meshes, small flower or small element don’t need shadows, it will only lag your game and will be almost invisible! or if player can’t see part, why don’t delete shadows too! windows don’t need it for example.

2. Why we need physics for that?

Disable can collide, can touch or can querry if element is small or player can’t touch it!

I’ll give you few examples:

  • Part are too small to touch it, because character will go through independently

  • Tools don’t need collisions, this will only bug the game

  • Part are blocked by others, for instance: window with two braces inside

  • Parts that inside something and cannot be go through, maybe small trapdoors or funnel

  • Plants, in real life you can go through them!

  • Doors, you can make hitbox that will close and will be invisible, and doors will be only an animation!

  • Thick parts: buttons,levers,fence parts ect… cannot be touched, because they blocked

3. Be aware semi-transparency

Semi transparent parts usually need more calculations to do than transparency 1 or 0

4. Stop using some materials if you don’t need too!
Glass and Neon need more calculations to do. They have reflectance or glowing effects, soo they are heavier than regular plastic or sand.

5. Avoid unanchored parts!!!

Unanchored parts have physics that are really heavy!!!, if you can, try to use unanchored things only when necesarry and try to anchor them after action you wanted!!!

B) Gui/Client/Effects

1. Choose the best technology

We have 4 technologies at the moment, every have different shadow generation/lighting handling, soo if you choose one, your game can be laggy or not. Try to pick the best for your needs and experiment with them, i have small knowledge about it, soo keep it in mind that this exists.

2. Make performance settings

One of the best options is to make settings, where you can choose how optimized your game should be. I’ll give few examples below:

  • Hight: Best graphic settings, realistic look of your game, or whatever you wan’t

  • Medium: Not realistic graphics, normal look of the game

  • Low: no clouds, no fog, no special effects, only things that not gives advantage to player

  • Very low: no shadows, and everything above, no celestial bodies, maybe smaller render distance(if you have it in your game)

3. Try to don’t use decorations you don’t need

Gradients, A lot of frames open and images can slighty reduce performance for lower devices, soo try to don’t use them like glitter everywhere.

Ok this was everything i know about light, soo if you wan’t more about that, ask profesional game designer, and now let’s move to scripting :}

C) Code & Scripts

1. Don’t use deprecated functions!!!

A lot of things were deprecated, for example wait(), yea it’s strange and a lot of people use them, but this is old methood that is unstable! Today we can use task library to make our work more stable and performant

Bad:

if db then
db = false
wait(3)
db = true
end

Good:

if db then
db = false
task.wait(3) -- more stable, and  2x faster!
db = true
end

Of course, there is more deprecated things, such as Velocity of parts , but this was only example.

2. Run Service over the while loop

When you making something that have to run every frame, you should use Run Service, it was created to make thing like Viev Models or other effects

Bad:

while wait(0) do
-- Code
end

Good:

RunService.Heartbeat:Connect(function()
-- Code
end

3. Preload things

Soo , try to preload things when you start game instead of every time, i show bad example of connecting function instantly, but you should make functions and acces it by events

local function Example()
-- Code
end
Event:Connect(Example)

4. Use local variables

Local variables can be used only in it’s scope, but they are more performant

If you defining service, or object at the beginning of the script, use them

Example:

local DSS = game:GetService("DataStoreService") -- you'll use this variable, not change it
local module = require(script.ModuleScript)

5. Use templates

Templates can improve your work with more read-able code and faster loading. For example you can make template part and then clone it, instead of doing Instance.new

However if you don’t wan’t to use clone, then keep in mind

Bad:

local object = Instance.new(ClassName,Parent)
-- you set propertiess

Good:

local object = Instance.new(ClassName)
-- you set propertiess
-- you set parent

this is example, you should load instnace into game after you set propertiess, then game don’t need to change them everytime

6.Think twice

This is easy, if you don’t need it in code, don’t use it! Think about what player/object can do, and how it can destroy code. And of course, test your code, you don’t need a lot of statements, use them only if important to not exploit or break entire game!

7.Split your work!!!

This step is very important!!! For first, you can handle effects on client and calculations on server.

I’ll explain this now.

When you have an enemy NPC that shoot arrows, you can handle 50% on client to make your server have less work, without making your game vulnerable to exploits. Here’s how!

For example, enemy shoots you with arrow, then server calculates a ray/part or something else, to check if player has been hit or not, you can set cooldowns

After this, remote will be fired to every client, where all animations and effects + audio will be played.

now, if you can sync server with client, you can make lag free system that looks amazing!

I have example video, thanks to gnomeCode in his tower defense series: GnomeCode’s Video:

8.Split work with your team

This is more about work performance, but it’s important too, you can split work across your teammates if you making game with someone to speed up work, this can make you’ll see mistakes and can correct it for the best results

9. Use modules and best methoods

Modules can help you handle tables and functions in one script, then you can simply acces your function once, not 40 times! Apart of that, choose the best methood of your work, i had a problem with player detection, soo i decided the hitboxes, because they run only when player will enter and leave area.

You can use bounding boxes to make hitbox and detect parts, they are well optimized and i’m recommending you them.

D) Other Tips

1. Don’t use humanoid!

humanoids are like salad, they have a lot of propertiess, calculations ect… that lags game.

If you have 100 of them, it can go pretty bad, soo is there alternative for them???

Yes, there is one good that will help you with little knowledge, here’s how:

  • If you don’t moving NPC, delete humanoid.

  • Move NPC via movers or constraints, not MoveTo()

  • Use custom health with bilboard gui

  • Use textures/meshes instead of clothing or accesories

2. Don’t spam remotes, seriously

Remotes can be hacked and are not needed in most cases. You can use bindable events to connect two scripts of the same type (STS, CTC) without going to client

3. If your game can handle it, use streaming assets or plugins
Soo, streaming is render distance, but remember if you enable it, you can simply destroy every script in your game, because render unload parts which isn’t in player’s range

4. Think from player’s perspective

This is important, maybe you wan’t to make something, but player will not use it, think about that

THE MOST IMPORTANT IS TO PRACTICE AND LEARN FROM YOUR MISTAKES!

Thank you for this tutorial, if you don’t agree with me, please tell me that, i can make something wrong, i’m scripter and i know only basics of building and animations. Anyway, good luck with your projects, and remember to leave a comment, your feedback is important too, bye!

75 Likes

Very good tutorial. Thanks very much for it, i will keep those in mind next time. it’s weird to see that it doesn’t have any comments yet.

5 Likes

i posted it 3 minutes ago soo…

2 Likes

There’s some good things in this thread but also bad things:

Changing the CastShadow property has no impact on performance, you could have 10.000 parts with or without shadows and the performance would still be the same.

Image from documentation:

Disabling collisions as often as possible is good, as well as using the simplest type of collision type possible. (box is the simplest, but might not be desired for all scenarios)

In the in-game menu, players can choose what type of graphics they want, lowest graphics already disables/simplifies many things.

The only difference between using task.wait() and a RunService method is when exactly the event happens, with task.wait() you can still run code every frame, you just don’t know when exactly it happens, but it can work for scenarios where you don’t care about it.

For humanoids, they can work correctly if you disable things within them, I believe they can also work better with StreamingEnabled, you don’t necessarily need to load every humanoids at the same time.
There’s also nothing wrong with MoveTo(), you just have to learn how it works.

10 Likes

Cool tutorial but I have a few concerns

then what if you want to have beveled body for an npc???

not everyone has a team unfortunately

It’s already a feautre in roblox??? even the lowest does your job

not everyone knows one professional game designer and not everyone have communication skills nor ways

Not every deprecated item harms performance and has an replacement

I’m sure it’s 99% who use local variables, also there are ppl who came from the python background, and python doesn’t have anything for defining variables, look at this code from python

user = "VSCPlays"
account_age = 2
print(user + " " + str(account_age)) # VSCPlays 2

I’m not trying to be rude to be honest, I’m just giving out criticism

also thanks to @Egzekiel for pointing out things that I said (I drafted this post before he even replied so don’t say that I copied his post)

5 Likes

thanks too, i can don’t remember things, and some are for teamwork, because many work with others

2 Likes

Ignore that I made a bajillion typos I will get onto fixing them

also I appreciate it

Edit: Fixed the typos

2 Likes

you know, when i told for example, don’t use deprecated functions, i mean some of them, region 3 is worse than bounding box now (tested performance) and profesional game designer, i should mention, ask at dev forum or someone who know it better than me, about local variables, it’s only thing everyone should do, and about humanoids, trust me, a lot of them is overkill for you. I tried to make tds game and humanoids…

3 Likes

I don’t think you’re correct, Region3 is a few microseconds faster than bounding boxes

though I do agree

5 Likes

seriously?, i tested and bounding box was better optimized

2 Likes

This comment is a bit confusing because you don’t specify what is faster about it.

Would be nice if you actually told us why the good example is better than the bad example.

1 Like

Basically for everyone else: Heartbeat runs depending on your frame rate (eg 60 FPS = 60 times a second), while wait() runs in 30 fps.

print(wait()) --> 0.03442870000071707 (there is another number, but its irreelevent)
-- this is how long it took

-- The Average number you will see with wait() and no parenthesis is 0.03
print(1/30)   -->0.03333333333333333 (How long it takes for a single frame in 30 FPS)
-- 33 milliseconds on Average
-- it will not be exact, but its roughly this amount

However, task.wait() exists, which runs the exact same as Heartbeat, but I would assume that it would be better handelled with an event because it takes more resources to run a loop than a event.

3 Likes

task.wait have 2x less time and it’s more accurate, and run service over while loop, it was for wait() not task.wait() because wait have unstable interval, and not everytime it will run every frame

1 Like

Ok this is still confusing, the real answer would be that task.wait() runs at 60hz where as wait() runs at 30hz.

The title says “Run Service over the while loop”. This is misleading because your argument is that you shouldn’t use wait() in a while loop. A more common interpretation would be that a while loop is worse than RunService, this is why it is confusing.

2 Likes

sorry, i’ll explain you:

while loop is less performant to make frame rate operations, it can come in handy when trying to make 8 frames or max 16, but not when you trying to make smooth , run service is more efficent and it has been created for that, + run service can be made every physic simulation, frame ect…

You are wrong.

while task.wait() do

end

and

game:GetService("RunService").Heartbeat:Connect(function()

end)

are the same performance wise

1 Like

but i don’t mean task.wait is laggy
loop is problem, loop need more performance to do, and heartbeat as i know runs every simulation, not every frame, soo if there’s no simulation complete, no function will run

Reply from DF:

It ignores the wait because it is an event, it runs everything the condition for the event to happen it met, in the case of heartbeat, physics have been calculated and so it runs the event, and once another event happens, it’ll run that code separately, unlike a while loop which respects waits,

You need to debounce the event to make it work like a while loop, respecting waits and what not

what about ContentProvider ???
This example is just BindableEvents than trying to explain how you should preload assets here.

Humanoids are not the reason game lags, it’s the DEVELOPER that codes it all and those listed in there are also not the reason to blame.

1 Like

trust me, 100 humanoids lag the game, i tested it myself