Optimizing for the Switch
I optimized sections of the game to improve its performance on the Nintendo Switch. Initially, the plan was to only release it on PC so we never encountered any performance issues. When we ported it to the Switch, however, our game encountered a number of problems.
When first loading the game on the Switch, I thought immediately that the game was broken. It wasn’t. The loading screen just took a long time, 53 seconds to complete. This would have been a game killer, so I immediately went to investigate. I first started by removing the art elements of our first scene, and quickly found out there wasn’t any change in loading time. The game had an audio manager that stored all our audio. I deactivated the “Preload Audio” setting to most of our Audio clips and talked to our Audio Engineer to further optimize the audio. This reduced the loading time significantly. I then reviewed the contents of the Lobby, and realized we had multiple objects that were not necessary for our first scene. I deactivated those game objects and added them to a list that delayed their activation until they were needed. This further improved our performance and brought our total loading time down to ~25 seconds.
The loading time was just our first hurdle. When we got into the game, it was running around a measly 20 fps. This made the game unplayable so I used Unity’s profiler once more to analyze our performance. The biggest issue was that we were allocating too much memory, causing stuttering to occur whenever the Garbage Collector cleaned up. After reviewing the highest spiking frames I made changes to key areas. A seemingly insignificant issue that was scattered in our codebase was our use of “gameObject.tag” to compare object tags. Getting the tag like this returns a new string so it allocates memory, and this was being called in high traffic areas of our code. I converted these to make use of Unity’s “.CompareTag()” instead, providing us with the same functionality without wasting memory. Another issue was that whenever we pushed blocks, we’d allocate memory. The game was allocating memory when it created new Lists to determine objects near the pushing player that it would iterate through each time. I refactored the system to cache a small List in the Start function and iterated through that instead. I also refactored our calls to things like Physics.Overlap calls to use their corresponding non overlap calls instead. By leveraging Unity’s profiler, I was able to refactor the unoptimized sections of our code and eventually bring our frame rate up to 60 fps.
There were other improvements I did including turning our Skins into Addressables, and going through our art assets to ensure our scenes didn’t make unnecessary draw calls. All this combined allowed us to release our game with a loading time of ~25 seconds and a frame rate of 60 fps.
When first loading the game on the Switch, I thought immediately that the game was broken. It wasn’t. The loading screen just took a long time, 53 seconds to complete. This would have been a game killer, so I immediately went to investigate. I first started by removing the art elements of our first scene, and quickly found out there wasn’t any change in loading time. The game had an audio manager that stored all our audio. I deactivated the “Preload Audio” setting to most of our Audio clips and talked to our Audio Engineer to further optimize the audio. This reduced the loading time significantly. I then reviewed the contents of the Lobby, and realized we had multiple objects that were not necessary for our first scene. I deactivated those game objects and added them to a list that delayed their activation until they were needed. This further improved our performance and brought our total loading time down to ~25 seconds.
The loading time was just our first hurdle. When we got into the game, it was running around a measly 20 fps. This made the game unplayable so I used Unity’s profiler once more to analyze our performance. The biggest issue was that we were allocating too much memory, causing stuttering to occur whenever the Garbage Collector cleaned up. After reviewing the highest spiking frames I made changes to key areas. A seemingly insignificant issue that was scattered in our codebase was our use of “gameObject.tag” to compare object tags. Getting the tag like this returns a new string so it allocates memory, and this was being called in high traffic areas of our code. I converted these to make use of Unity’s “.CompareTag()” instead, providing us with the same functionality without wasting memory. Another issue was that whenever we pushed blocks, we’d allocate memory. The game was allocating memory when it created new Lists to determine objects near the pushing player that it would iterate through each time. I refactored the system to cache a small List in the Start function and iterated through that instead. I also refactored our calls to things like Physics.Overlap calls to use their corresponding non overlap calls instead. By leveraging Unity’s profiler, I was able to refactor the unoptimized sections of our code and eventually bring our frame rate up to 60 fps.
There were other improvements I did including turning our Skins into Addressables, and going through our art assets to ensure our scenes didn’t make unnecessary draw calls. All this combined allowed us to release our game with a loading time of ~25 seconds and a frame rate of 60 fps.