We have been Beta Testing our soon to be released game The Dog Run and it’s been mostly OK but we had a number of issues with memory on smaller or older devices. We made some gains with modifying our audio files (See this post) but were still running into niggling crashes on start up and longer than normal load times.
We were getting feedback like:
“Hey, I installed the game and couldn’t run it. When I started it there was a black screen for about 15s and then it went back to the launcher. Then each time I went back to the game there was unity and game logo fading out and again the app crashed/hanged and I was sent back to the launcher.”
(Thanks slomoian and the_blanker for all your help testing)
Obviously feedback like this is a little disheartening and far from ideal. The game was running fine on every device and emulator I had access to but it’s only when you send something into the wild that you realise the full breadth of the spectrum that is the Android platform. I guess this is another lesson in the importance of proper Beta testing. One we hadn’t learned last time we released an app (see this old post on the perils and difficulty of finding Beta Testers).
We were using adb logcat to monitor our start up problems but not finding a “smoking gun” that solved every case. It seemed to be a memory problem and often with the graphics cache so again we went back to the Unity Editor build log to investigate our image files. The game uses multiple large files to ensure that our animated sprites were always in the right spot. The game is dependent on the titular Dog hitting the ground line accurately on every frame to achieve the look we wanted when he runs and the paw breaks the ground line and appears as a gap. We used a “flip-book” old fashioned style of animation where each frame sits exactly on top of the old frame and everything lines up on a transparency like in classic animated movies.
By using this schema we had to keep to a certain scale that fit within the constraints of a typical Android device format. This meant that when the images were imported the POT was not going to be something we could play with easily to get performance gains. (Image files that have a width and breadth that is a power of 2 are faster and easier for the compression functions to work with – so 2, 4, 8, 16, 32, 64, 128, etc). If I had the chance to do this again this is something I would probably start doing right from the beginning of development. When going through the Editor Logs we did find something interesting (get to the Editor Logs by right clicking on the arrow or tab near the Console and selecting it).
We found that some of our image files were 10 MB and a few were 2 MB. Which was a little weird as they were all exported as layers from the same Gimp file so I must have done something in the import settings or the editor to change them.
This is a comparison of two files of the same dimensions and basically the same content but with two very different file sizes:
10.6 mb 0.8% Assets/artwork/RunOnSpot6.png
2.0 mb 0.1% Assets/artwork/DogSitHeadWag.png
The difference that I found was MIP Maps. I’d selected to use MIP Maps fairly early on as it made the art work look smoother in the Editor. MIP Maps are generated in the engine to make smaller more compressed versions of your artwork that can be used at longer distances from the camera where the detail is less visible. My game is 2D and has everything running at pretty much the same distance from the screen so really MIP Maps should not be required. My art did look a bit better in the editor with them turned on but on a smaller device like a phone I couldn’t really tell the difference. See below the difference in a file with MIP Maps selected and a file without.
With MIP Maps turned on (see the file size at the bottom and that the type is RGBA 32 bit):
The same file with MIP Maps removed (down to 2 MB and using ECT2 compression):
This is the difference that generating those MIP Maps makes. Your file is converted from the Android default compression to a larger (harder to process) 32 bit compression format.
So by turning off MIP Maps across the three hundred plus image files in my game reduced my application start up time to under a few seconds and reduced the APK file size by over one thousand MB.
This is the Build Report from the Editor Logs that shows the larger texture sizes and final build size:
Uncompressed usage by category:
Textures 1292.3 mb 94.6%
Complete size 1365.9 mb 100.0%
Compare this later Build Report with MIP Maps turn off to the original one above:
Textures 284.5 mb 82.6%
Complete size 344.6 mb 100.0%
It’s a considerable difference with little or no quality loss on most devices. When I say most devices there were a few cases where the running dog did look a little tatty. On very small emulated devices (3.5″ screens and low memory) the images were being scaled down quite a lot and the results were a lot less enjoyable but still an acceptable compromise considering previously the game would not run on these devices at all.
The next thing I started playing with was the different texture compression variables available for Android. I tried all of the settings (see screenshot below) in a different build and tested them against at least ten different devices with various architectures and screen dimensions and Android versions.
In each of the cases but one there was at least one test device that failed to start the game. Once again exposing the issues of working with so many platform variables on Android. Even when I built the APK with the (default) ETC selected one device failed the start up test. So in the end the final build used the “Don’t override” setting which seemed to work on all devices.