After 4 indie games released I've learned many things about optimizing my games for mobile. At first I was very inexperience about what I needed to do and to be honest didn't have much exposure to optimization because I had never released that many games before. I now have a process where I ask a simple practical questions that I think everyone should consider before releasing to mobile.
How much are you willing to give up as far as art style for the cost of performance?
I ask this question every time I work on a new game and it is critical as you need to be aware of the cost or at least find ways to still be able to keep the aesthetic aspect somewhat close to your original goal without affecting the gamer experience.
Let me walk you through few tips and explain in more detail what I had to deal with in my own games. I am also going to explain the reasons that went about optimization and why did I spent so much time on that part of the game development process. Also, by no means I claim to be an expert in the subject, but I do have first hand experience on what improvements I had to make in order for my games to run in optimal form.
Real time shadows (hard shadows vs soft shadows)
Yes, I love real time shadows and they look amazing in games, however there's a huge performance cost that goes into enabling them. At first it may look great while playing the game in the editor, or easy to enable by going to your light game objects and just turning on "Real time shadows". Then at some point in time you run your game in your mobile phone and quickly realize that FPS goes from probably 60 to a much lower number and now you may be getting huge drops. You may also find that in latest mobile phones real time shadows may run fine but your game is causing the battery to drain dramatically. This is due to real time shadows and yes that's right shadows take a lot of CPU/GPU computational power. Another huge performance expense comes by using soft shadows, however these are just a cost to your GPU.
What did I do to optimize shadows for my own games?
I decided to disable shadows completely in both versions of "Cubiques", I was averaging 20-50 FPS with real time shadows when running on an iPhone 7 Plus and this device was powerful so it didn't really make sense to have such a low FPS even with a powerful mobile device so I knew I had to fake shadows if I wanted to keep the same look and feel. Now fake shadows? Yes, if you've ever seen Cubiques you may have noticed that everything is made out of a Cube. To fake a shadow all I had to do was project a plane with a negative offset in the Y axis, add a simple light gray color to a mobile shader material, and each tile needing a shadow had its own fake shadow with the same setup which made it look like a real shadow.
The image below shows you how a real time shadow looked versus a fake shadow. Also notice how similar they are but how much was gained from computational power.
Just from this modification the game went from 20-40 FPS to a consistent 60 FPS. Also my mobile device was not eating up battery or getting super hot. In addition to disabling and faking shadows, I initially played with shadow distance which helped me improve realtime shadows which in the end didn't use. As a side note, distance shadow can help in making sure you don't have shadows in objects that are too far. Quality settings on shadows can also help, play with these settings until you're somewhat happy with the results and performance, see image below.
There is also a good read on baking shadows which I didn't cover because I haven't used them just yet. Take a look at this article by Unity in their documentation.
I didn't measure this but I did experience improvement in performance after making this change. First you must identify all the objects in your scene that won't move. In my case most of the scene game objects were static, meaning the only ones that really had any kind of movement were the main cube characters. To enable static batching just set each object as static which is a property every game object has and can be set through the inspector. Also make sure the player settings has static batching enabled under the rendering section.
The image below shows few selected static game objects:
What I noticed was that meshes couldn't be moved in the editor window which in fact did what it said during the configuration, these objects marked as static shouldn't have any movement and therefore not movable through the editor at runtime.
Unity has a lot of options for image compression, the one I found to be the most optimal for UI elements was the lower tier for iOS devices which is "RGB Compressed PVRTC 2 bits". In my case the UI looked great even with a low compression, however you probably should review the different options based on the platform. Also keep in mind that Unity provides platform specific overwrites which makes it very powerful when needing to optimize your textures based on your platform.
See image below for how you can set the compression based on platform:
Also, compression can save you a lot of space when it comes to the size of your build. You want to make sure your final build is as small as you can as players are very picky when it comes to saving their phone drive space, in addition Apple requires a WiFi connection whenever apps are above 100 MB so you may want to stay within those boundaries if possible or at least somewhat close.
For audio compression I followed this great article that talks about exactly how you should setup compression based on the audio type. Here's a break down on how I set audio compression in my own games.
- Short Clips – Native
- Longer (or looping) clips – compressed in memory
- Music – Stream from disc
- Files which consistently cause CPU spikes – Decompress on load
Post processing Stack
The new post processing stack from Unity is amazing, yes it makes your game look beautiful but as I said earlier, aesthetic beauty can and probably will come with a big cost.
When the post processing stack came out all I wanted to do was enable every single option. Bloom, motion blur, Ambient Occlusion, Vignetting, Color grading, etc. These options look beautiful and can give your game a beautiful post effect that you wouldn't be able to easily achieved otherwise, however each option has a cost, just like everything in life does right?
Anyhow, I tried two versions that Unity offers. They currently have two branches in Github one called V1 and a second one called V2. Both are great and they both have their own pipeline and without going into much detail, I can say that certainly V1 didn't work well for mobile devices. I tried it with iPhone 5 all the way to an iPhone 7 Plus and FPS was terrible. V2 somewhat improved had options for "mobile optimization" under each effect but I wasn't very happy with FPS so decided to only use one effect "Vignetting" with a mask which in my case didn't caused any kind of spike in FPS. Also, I want to make sure you try both branches V1/V2, I didn't do too much research here because few of the effects I really wanted such as AO and Bloom were too costly so to me it didn't make sense to have it in the game.
See image below which shows V1 usages for Cubiques
To summarize, there're a lot of steps you can take and learn from this article. Also, there are many more I didn't mention and honestly you will find as you do performance optimization in your own games. I didn't mention many aspects of it which I assume to be known such as using the profiler in Unity as you try each optimization step, play test as you make modifications, and make sure to be committing to source control each time to try something new as this allows you to revert back in case of an incorrect change made.
I also want to provide you with few helpful articles I read and I believe will be helpful for you:
- Reducing the size of your build.
- Texture compression formats
- Light troubleshooting performance
- 4 ways to increase performance of your unity game
- Optimizing mobile applications
Thank you for your time and don't forget to subscribe to my newsletter, also be sure to find me in twitter at @dilmerv and stop by and say hi as I love to chat with everyone.