OPTIMIZING iOS GAMES IN UNITY FOR UNIVERSAL BUILDS PART 3: GUI, SOUND AND PROFILING
Interface screens at Retina resolutions can eat up a lot of atlas space. What we found is that you don’t need to match a 1:1 resolution to maintain sharpness and quality. While some level of eye testing is required to find the ideal cut off point we found we could crunch atlas sizes down to 1/3 the size. This is especially helpful when dealing with phones that can not load 4K images and therefore require multiple 2K images. An example where we benefited from this is in our Tower Upgrade menus. Despite Retina enabled iPads having a native resolution of 2048 x 1536, we managed to fit all the UI elements in one 2K image cutting down from the initial 3 X 2K atlases we were using. Another useful technique we found using NGUI (a separate UI plug in for Unity) was the feature to lock your borders. For example, if we you use flat colors on your buttons with a thin border, you can lock the borders and scale up the flat color to any size without getting pixelation. This will let you make buttons of any size with one texture.
TOWER UPGRADE ATLAS
The sound went through some changes as well to reduce load times and lessen the calls on the processor. While we initially wanted directional, uncompressed sound, we had to arbitrage with tech and art to get everything in. Interestingly we discovered that during runtime mp3 files use more memory resources than wav files – even though wav is an uncompressed format. We used single channel 44100khz 16bit files with dynamic loading for assets in a particular level to get the best memory use.
Xcode and Unity profilers are crucial to detect any memory leaks while the game is running on device.
Xcode profiler gave us detailed data about the memory usage of our game and a sense of what the optimal memory usage should be. We found that the memory threshold for iPad 2 was around 220MB and iPad 3 was 400MB. As long we stayed below these values, the game would run smoothly on those devices. The ’Activity Monitor’ in particular was a very useful tool. The monitor shows you the memory usage of all the running apps on the device and if your game is attempting to eat up or leak into the memory of those apps. Normally, if there is a memory intensive asset loading in our game and there is not enough memory available it will actually unload the running apps to free up the required amount. We wanted to avoid any such leaks or instability and the Activity Monitor helped us achieve that.
The Unity Profiler displays the actual game assets being loaded into the memory. This was advantageous in particular when dealing with atlas sharing in our game. Initially, we had an enemy sprite that was sharing a teleport effect from a boss atlas which was 2k. Once we started using the profiler we realized that the entire 2k atlas was being loaded during runtime which was consuming a lot of memory. To solve this problem we simply created a small common atlas with that effect which could be shared among sprites in the game if needed.
We also wanted the game to run smoothly on lower devices, specifically the iPad and iPad Mini 1st generation. Due to hardware restrictions we did a couple of things to make sure the game ran on these devices. We first detected what device the game was running on and if it was a lower end device we:
- Deleted particle environment effects such as glows, lava flowing, etc.
- We put in a creep cap that would set a max threshold for total number of concurrent enemies on screen. If a wave went over that cap or a player was having trouble getting rid of a lot of enemies, the game would wait for the creep cap to open up spaces before sending in the rest of the wave. We really debated this internally because we felt it would make the game easier – but in testing we found that since there was so much going on, you barely noticed.
- Lowered the sub boss and boss atlases from 2k to 1k.
In conclusion, striking a balance between quality and performance was definitely a challenge, but a rewarding one nonetheless. Seeing a single, universal build running smoothly on all iPad devices was very gratifying and made all the hard work worthwhile.