Unity UI System - Best Practices
Tags: gamedev, videogame, unity3d, development
Published: 2024-04-26 09:35:28

During my development days, I've seen many Unity projects. Sometimes I've made them from scratch, other times I've continued someone else's project.

In either case, when I had other developers in the team, I noticed that a lot of them had trouble with Unity's UI system, whether it's scaling of components, optimizing rendering calls or just plain structuring of game objects.

I noticed that most of them didn't follow any guidelines and just worked based on their feeling of the best practice, which often turned out to be wrong. But that was also true for myself, until the experience taught me better. 

What I also found to be the problem is lack of summarized material for my cases, when I didn't want to waste time going through whole documentation. So this is my attempt to summarize key points and solutions that I've acquired over the years.

**Disclaimer:** note that these are not the official guidelines, and they might not be convenient for every type of project (VR for example) - but these are the ones I've found to be most effective for most projects that will run on screens (mobile, PC, PlayStation, Xbox).

## Canvas Component

The only way to start this discussion is to talk about the main UI Component - Canvas. Canvas is the main parent object, that contains all the UI components as children. I will not go into detail about how it works but instead, talk about two key properties when setting it up:

**Canvas Render Mode**

You can choose among 3 options: Screen Space - Overlay, Screen Space - Camera, or World Space.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e8lrfd5h8gk9fjhuf4r9.png)

The main difference between **Screen Space** and **World Space** is that **Screen Space** will render **Canvas** in front of the whole game world; basically, it will be fixed on the user's screen in front of everything else. Meanwhile, **World Space** will be rendered among other objects in the game world, and it can be anywhere, like a regular object that is not a part of UI.

In most cases, your choice will be **Screen Space**, as the UI components are mostly used for UI indicators inside the game that are always in front of the game world (such as health, inventory, number of lives, timers, etc.).

**Canvas Scaler (UI Scale Mode)**


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/so5lrv8f8de73wagu606.png)

This is probably the more important part of the **Canvas** setup - specifically the **UI Scale Mode** property. By default, it's set to **Constant Pixel Size**, which can cause scaling issues upon changing resolutions if left like that. In most cases, **UI Scale Mode** should be set to **Scale With Screen Size**, which will give you an option to set default resolution and make objects in UI scale, either with width or height, upon changing the resolution.

Example of Canvas settings for Mobile UI:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hzfqmwkolr7fs6bhmisp.png)

## One Canvas or Multiple Canvases?

This depends on the use case. Before answering the question, let's talk about draw calls in Unity and re-draws explicitly on **Canvas**. Let's say that you have one **Text** component inside canvas which shows the seconds passed since the start of the game. That means that each second, your **Text** component is going to change. Every time a component changes, the **Canvas** that contains that **Text** is completely re-drawn. Now let's say, that you have a few static **Image** components inside that same **Canvas** with **Text** timer. Now, each time a second passes, **Canvas** is completely redrawn, meaning that not only **Text** will be redrawn, but all the static **Images** (which technically don't need that redraw since they didn't change). You can imagine how that issue can scale up when you have multiple components that change inside one canvas - **and that's where the second Canvas comes to save the day**.

If you have **Canvas** nested inside a **Canvas**, when child **Canvas** is redrawn, the parent **Canvas** will not be influenced. So the smartest structuring of the game objects would look like this:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c7munsgylfi5s2t0defx.png)

This knowledge of **Canvas** redraw behavior can greatly help when optimizing the game for lower-end devices. Think about it all the time, and it will most certainly improve your game's FPS.

## Image Component

**Image** component is pretty simple by itself. The main challenge is making sure that the image will appear the same on different screens (resolutions). To ensure that behavior will happen, just make sure that **Preserve Aspect** is ticked. This is how the **Image** component should look:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vod335ne44e34cca47qy.png)

The second part of making sure it looks the same on every screen will be explained in the Anchoring section.

## Text Component

Like the **Image**, the **Text** component is also pretty simple and presents the same challenge - making sure that it looks the same on all screens. This can be ensured by setting a custom **Font Size** and making sure that **Best Fit** is unticked! If **Best Fit** is ticked, the size of the font (text) will vary from screen to screen, as Unity (and Canvas) will automatically change it to what they think is best fit, and you will get inconsistent UI as a result.

Here is an example of how **Text** component should look like:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e41i5w72kywkt2wusi46.png)

The second part of making sure it looks the same on every screen will be explained in the Anchoring section.

## Anchoring

Anchors define how your UI component will behave in relation to its parent, and it can be set on each object that has **Rect Transform**, or in other words, is a part of UI. They look like this by default:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s3p6fvo1qio648qu55ef.png)

You should never leave them in their default position. By clicking on the Anchor Rectangle in the Rect Transform, you can select predefined anchor positions (top, bottom, left, right, middle, each of the corners, etc.). That menu looks like this:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dqyqls6b3yplcfje21ex.png)

However, what I suggest to ensure that every object will be placed exactly as you've set it up, regardless of screen resolution is to drag by hand each anchor to the corner of your UI Component. In practice, that would look like this:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zacy7s59gujibdb7m6ns.png)

This way, however you change the resolution, the object will stay in the same position in relation to its parent.

## Conclusion

I hope this basics of UI have covered some of the troubles you are facing and managed to put you on the right way of building the best UI. Happy game creating!

Luka Ćurčić