How To Optimize a Unity Game

I wasn’t sure if there was a better spot for this so I’ve put it here.

I’ve written a guide that basically covers everything I’ve found helpful to optimize my personal Unity projects so far. It’s not intended to cover absolutely everything, but it’s a good summary of general principles that worked for me.

You can see the article here: How To Optimize a Unity Game – Stuart's Pixel Games

If you know of any other optimization tips, please feel free to add them here or on my blog post as I’d like to keep updating it.

2 Likes

I don’t have time to read the whole thing yet but I’m confused about one item that you wrote:

Not sure what the “Event Editor” is. I’m wondering, though, if the texture is just a solid color, why would you need to scale it up? I’m assuming by “scaling it up” you mean up-sampling it. If you do this then how does it save memory?

When I do a fade to black effect, I take a single black pixel image and stretch it across the entire screen, then fade it in. I’m assuming @GameDevSA was referring to something like that.

2 Likes

In that case I wouldn’t call it scaling-up the texture, but rather the mesh that it’s mapped to. That paragraph could use more precise language for clarity.

1 Like

Oops that’s a typo, thanks for pointing it out. I merged some parts from an optimization guide I wrote from another game engine, still applicable but different language. Thanks for the catch!

In terms of scaling up though, my understanding is, if your game is say, 1080 x 1920, and you create an image that is solid black that is also 1080 x 1920, that you’re wasting resources because an image that large uses up a lot of space. The game file becomes larger, but also uses more RAM.

You’d be using less memory by making the image 27 x 48, then scaling it up 40x, for example, or so I understand it. Or yes, even using one pixel and stretching.

I’ve updated that part now.

That’s a fair point if you are working in 3D with meshes, which I don’t, I make everything with sprites in 2D so you just scale it. I’ll make a change.

You don’t even need a texture. A blank ui canvas image will fill rectangle with its color.

2 Likes

Ah, I see. Well, sprites in Unity are also just textured meshes behind-the-scenes, so it’s really the same thing either way.

I wasn’t aware of that, thanks!

1 Like

Just off the cuff:

-Culling

-Batching

-Pooling

-Limit AI cycles

-LOD for colliders, art, and scripts

-Imposters

-Force the Garbage collector at appropriate times

-Use rays instead of colliders when possible. even if it’s a projectile, you can do a series of ray casts on a moving point.

-avoid mesh colliders when you can use primatives

-use box colliders that have a 0,0,0 rotation (cheapest of the colliders)

-use 2D colliders when possible. Even if you use 3d models, if it’s on a 2D plane do 2D colliders

-multithreading

-I’m really not sure how this is done, but optimize CPU memory. That is, load the CPU with relevant data to avoid having to pull it from the RAM when possible. I’m at a total loss as to what this is called or any tutorials in it, but I know it’s a thing.

-static methods that have multiple functions

-use particle emitters when possible

-use animations instead of manual movement when possible

-avoid the built in RNG when possible

-use int instead of float when possible

-run an asset clean up tool before building

-use A* method instead of navmesh when possible

-build the game instead of running it in editor to see actual performance

-identify your bottleneck between the GPU, CPU, and RAM. It’s usually only one slowing down that is giving you issues

-pro builder is can be a resource hog

-stagger processes when possible. As an example I’m making a shotgun. Rather than doing the math for the spread when pulling the trigger, I’m doing the math for each pellet one frame at a time before hand, and when I pull the trigger doing whatever pellets are not done.

OR another example is rather than having all of my enemies do decisions every frame I’m doing them in chunks taking turns. There’s lots of ways of doing this. Some prefer to give them a clock to do it every so often, rather than every frame. Some prefer to make an array and cycle through it.

-cache rather than find when possible

-I’ve had a lot of success with this, if you have a complicated collider do a large simple collider that turns on the more complicated colliders

-avoid changing variables and GUI elements every frame, and instead only do so when they change

-avoid instantiate and destroy like the plague (see pooling)

2 Likes

How optimal is that?

Some very good comments there, thanks! Some of that I think I covered but not all of it, I’ll go over this in detail when I have more time and might query you about a few things. Cheers!

1 Like

It should be optimal.

If you want the absolutely fastest way to draw a colored square that’ll be an unlit shader with a single parameter.

Sorry, but of all the things that can be optimized, why the focus on this?

Just clarity.

It’s avoiding cache misses. Search for Overbyte’s blog about optimising the game Vessel for info on it. The author also previously gave talks about it for Sony, and the slides for that are publicly available, too. From memory, search for “Pitfalls of Object Oriented Programming”, I think that was the name.

Edit:
http://overbyte.com.au/index.php/overbyte-blog/entry/optimisation-lesson-3-the-memory-bottleneck

Edit 2:
https://m.youtube.com/watch?v=VAT9E-M-PoE

2 Likes

Oh wow!

we all forgot a huge one.

DOTS!

Found some amazing rendering performance improvements for repeating meshes using the Graphics.DrawMesh commands but they are runtime specific and tricky to use and understand.

I think Unity could make rendering performance optimisation a lot easier with features like this but implemented into the editor/component system as simple to use and profiler detectable scenarios for using them e.g. Unity detects that you use the same mesh multiple times in a scene and recommends adding the DrawMesh component or enabling the DrawMesh toggle in the editor.

1 Like

Unity already has mesh batching. The DrawMesh stuff is for the many cases which aren’t easily covered automatically.

1 Like

I can’t help but think the real win here isn’t the coding or techniques at all, but just load management. You’d want to keep all your game dev stuff simple and even wasteful at times, just whatever makes the program operate correctly.

This is usually slow, so you’d implement load management, basically the first call of optimising something is… don’t do things if you don’t have to.

In a typical game this means LOD affects not just the models, but the scripts as well. Enemies will update less frequently, and animate less frequently the further they are, or if occluded. Any running scripts politely disable when not required, or update with much less frequency.

Things like this - most people can build a game using Unity’s wasteful learn approaches and still ship @ 30 or 60fps on the target platform.

For VR it’d be tighter, but for everything else, and readers of this thread new to Unity, I really do recommend that you focus on the program behaviour and later, how often that behaviour needs to be processed.

I think, after all the zen black ops optimisations I’ve done over the years, this is the biggest win, every time - and the easiest.

4 Likes