Testing and optimizing mobile UI performance is a crucial part of the design and development process, and integral to any game’s success.
For the second part of this interview, we return to our discussion with Outfit7’s Senior Software Engineer Aleksander Gregorka, Samsung’s Developer Relations Engineer Søren Klit Lambaek, as well as Unity’s Senior Technical Product Manager Benoit Dupuis, to get their best practices for shipping a highly performant game with an enjoyable player experience.
In part two of the Q&A, they share details on implementation, testing, performance optimization, and analytics integration for UI.
Let’s pick up where we left off: What are some best practices for implementing a user interface without coding?
Benoit Dupuis: If you use Unity UI, there are simple ways to prototype a functional wireframe by activating and deactivating elements of the interface with Unity Events. These are exposed in the Inspector with certain interactive UI elements, like buttons or toggles. You can add the GameObject to the Unity Event and select which action to trigger when a button is clicked, for example.
This example simulates a navigation flow that enables a GameObject. The OnClick Event turns on the GameObject called NewPopUp by calling SetActive(true), and then disables the PopUp GameObject.
Here are a few other tips to keep in mind:
Above, you can see UI Builder, followed by the code below. Your hierarchy of elements – the Visual Element Tree – will be scanned in the code and register the elements that need interaction. For instance, a play button will be saved in a variable, and when the button is pressed, you can listen for callbacks. The only information that the designer and programmer need is how the button is called.
We recommend the Block Element Modifier (BEM) naming convention for your visual elements and Style Sheets. At a glance, an element’s BEM-style name can tell you what it does, where it appears, and how it relates to other elements around it.
Examples of BEM naming:
How can you architect the codebase to integrate and test various UI changes?
Aleksander: Decouple the logic from the view components. It’s hard to plan for UI changes, but remember that UI views shouldn’t be doing any logic changes. They should only display what’s being sent to them, either directly or by observing values and receiving events. In this case, you can simply replace the rendering logic when needed, even if the whole UI system changes.
Who is typically involved in the testing phase of your UI?
Aleksander: We have different approaches when it comes to testing our UI. One of them is what we call “user testing,” where we invite users from our target audience to play the game. We observe their behavior in the game world and take notes, then we adjust the UI as needed.
Another approach that we take is what we call “internal testing,” where our employees test our games and report any issues that they encounter. We usually get tons of useful feedback from them because they only expect the best UI and have tons of relevant experience.
How do you test foldable UI if you don’t physically own a foldable?
Søren: Samsung provides Remote Test Labs. We’ve set up many physical devices, and anyone with a Samsung account can select a device and book a timeslot. The system allows you to upload an APK file and test it on various physical devices.
What are the biggest performance killers for mobile UI?
Aleksander: The biggest performance killers for mobile UI are overdraw, rebuilding the Canvas too often when you have dynamic elements, long Canvas rebuilds if you have a lot of elements, and text mesh generation. We’re mindful of these for our game projects because we have to support a wide range of devices.
Søren: UI can become slow if you use very large raster graphics, so make sure the graphics you use fit the allowed memory capacity of your device. Rendering 3D graphics to your UI on the fly can also take down performance significantly. These include minimaps and character inventory systems.
What are your top tips for UI optimization?
Aleksander: Group UI elements into different Canvases (or child Canvases) to avoid excessive Canvas rebuilds. Whenever an element changes, the whole Canvas is dirtied and needs to be rebuilt. This can get quite expensive, so it’s better to put the dynamic elements into their own Canvas, or even more of them.
Avoid layout groups whenever possible, especially if nested, as they will dirty your Canvas. If you have static items, it’s better to provide precalculated positions and sizes.
Disable Graphic Raycasters and raycast targets on non-interactable UI elements. The Graphic Raycasters will try to figure out if your touch was within the UI component, which can be expensive.
Similarly, disable background cameras if you’re displaying fullscreen UI (think of dialogs). This way you can avoid the extra rendering cost of occluded cameras.
Use Texture Atlases, but think about how to spread the sprites across different Atlases so you can load the appropriate Atlas when needed to reduce memory consumption.
Lastly, the most important tip is to actually profile the game on the device, and then decide what needs to be fixed. It’s never good to blindly follow lists of things to optimize.
Benoit: For Unity UI, it’s commonly recommended to separate elements into Canvases based on whether each element is static or needs updating. Each Canvas, when updated, refreshes all the child elements, so it might be worth only doing this with elements that actually need refreshing.
It can also be beneficial to avoid overlapping transparent pixels, but rather flattering visuals of UI elements as much as possible. One way to possibly reduce the number of elements is to create sprite images for UI elements that spawn during runtime; those that can be flat images, for example, single-digit visual indicators onscreen, or predefined sets of emojis. For more details, check out this e-book, which has a specific chapter on UI performance.
How does UI impact the performance of a mobile game on Samsung devices?
Søren: So far, we have not come across UI taking up much of the performance. This isn’t to say that it doesn’t happen. I could imagine it happening if the design becomes particularly complex, or if the UI components, such as minimaps, are not implemented carefully.
Can you benefit from Adaptive Performance as it relates to the UI design?
Søren: You can use Adaptive Performance for UI design – however, for 2D raster graphics, be careful not to overdo it as it will often end up with blurry or other unwanted results. Adaptive Performance might be more suitable if you render 3D geometry to your UI layer on the fly.
In terms of resource management and runtime optimization, is it a better practice to make a larger, unique art asset for every panel, or a library of smaller parts that can be assembled and layered together?
Aleksander: It depends on the use case. Performance-wise, it can be beneficial to use larger art assets, but generally, it’s safer to use a library of smaller UI parts. We’re constrained with app size on mobile, so we try to use 9-slice scaling as much as possible.
Building a UI element Prefab library can be really beneficial when starting out with a project. In the beginning, it takes a bit longer, but once you have it, you can quickly reuse components to build your UI at speed. What matters most is that you’re being consistent with your art style throughout the game.
Benoit: If the game using Unity UI is highly stylized, it might be worth having an image for those hero pop-up menus for runtime performance. But in terms of texture size, it’s always recommended to use features like slicing in the Sprite Editor, and reducing the number of child UI objects as much as possible.
How do you go about managing autosize for text, while keeping localization in mind?
Aleksander: I believe the best way to manage autosize is to not have to. If you can afford some screen real estate, it’s better to expand the text areas that will fit all the required localizations, or prepare some presets for different languages if texts are not dynamic. When using autosize, make sure that you’re not updating the text for every frame if it’s not needed. In any case, remember to test every localization on all the added text to see how well it fits onscreen.
Do you integrate analytics into your UI workflow to validate the effectiveness of your design?
Aleksander: We have our own analytics workflow that covers all aspects of our games, including UI. We measure which UI elements were clicked or ignored so we can make decisions based on that data.
We mainly focus on UI elements that are tightly related to our key performance indicators (KPI), such as rewarded video positions, in-app purchase (IAP) offers, and others. We also experiment with onscreen heatmap visualizations for further insight into player behavior.
The main takeaway for mobile designers and developers is that there is not a one-size-fits-all strategy when it comes to testing, optimizing performance, and analyzing data for UI. Each situation is different, and it’s important to keep these best practices in mind to help ship the most performant game possible.
Want to know more? Read our new e-book on user interface design and implementation in Unity. We also invite you to share your tips for success with other users in our Made with Unity forum.