Sea otter in a circleSea Otter Games

#2 - First steps with Unity's UI Toolkit

By Hugo on 2023-11-26
Game Development
Unity
Tutorial
UI

On my way to achieving an MVP for my game, having a functional, decent and maintainable UI seemed extremely important. It was also quite adventurous as I know little about front-end development and design. I was still confident until I saw my old-school Unity UI and the mess that was the canvas object I had made a few years back. I am sure you are familiar with some of the horrors a large UI can turn into, well that was it.

My old UI had tons of issues. To name a few:

By far, the worst part was the radial menu used to select buildings. I created it in a sort of creativity-driven rage over a few days before forgetting my project for another 6 months. Yeah, that kind of feature šŸ™‚...

A view of the radial menu for each environment.
The radial menu for each environment. It targets a tile and supports zooms and camera movement
Unity component hierarchy of the radial menu. It is massive and shows that the component is hard-coded and replicated three times with variations.
The component hierarchy - I hard-coded the menu and replicated it for each environment type
Unity component view of the radial menu. Each variation of the menu has to be manually set up in the inspector.
The component view - The menu packs very little logic, everything is setup in the inspector for each situation

Look at it! It's ugly. No one could possibly figure out why I chose 4 building slots to start with. Any changes would require redrawing all the assets, modifying the scripts or adding new copies of the whole menu. It is also a huge system that watches the mouse's position and scales and moves with camera zooms and movements. This was overkill nonsense, it had to go!

In Unity, the "standard" UI system scares me. The distinction between elements, styles and behaviors is not clear enough and it entirely relies on your implementation and quality of code. As such, I searched for a tool to make the task easier. Hopefully, I could find something with an editor window. That is when I came across UI Toolkit. It is a free package built in Unity which came out in 2020. There is a bit of controversy surrounding it because its development took much longer than initially estimated and because. Furthermore, as of today, it does not fulfill all its promises in terms of features. But Iā€™m sure it will be good enough to build a sturdy UI. (hopefully I wonā€™t regret writing this... )

Without further ado, letā€™s dive into it!

How to set up a static UI Element ?

A current view of the game. In the bottom left corner, you can see a UI element indicating the amount of each resources. It is a number next to an icon.
In this guide, I will show you how to create this resource inventory (bottom left corner)

šŸ’” UI Toolkit is built in Unity but if you want to change the version, it is available as a package called com.unity.ui.

Start things off by creating a folder in your project hierarchy that will hold the elements UI Toolkit produces. UI Toolkit does not generate many files, which is appreciable. It uses a UXML representation for UI elements and stylesheets similar to CSS for the styles. With UI Toolkit, you have the clear separation between elements (UXML), style (stylesheets) and behaviors (c# scripting) I was looking for.

Then click on Create > UI Toolkit > UI Document Document. This is the aforementioned UXML document which will hold the body of your UI Element. After opening it, you should be met with the UI builder editor window. From here you can drag and drop various elements in your hierarchy on the left and modify their components on the right.

A view of the UI builder editor window of UI Toolkit
The UI builder editor window

Now, to create our component, we have two things to do: drag and drop the right elements and tweak their settings. Easy right? Well not exactly... First, letā€™s focus on visual elements, these are the basic containers you will use to split your component. Think of them as HTML divs.

A view containers list in the editor window. You can drag elements from here.
The visual element can be found on the right-hand side of the editor window

Use them to plan ahead the architecture of your component. In this situation, we want something similar to this: a component holding three identical rows which all contain two elements side by side.

A schema of the component architecture.
Here is a nice schema made with paint šŸ˜ƒ

The main visual element (dark grey) holds three visual elements (the rows - in white) which all hold two visual elements (light grey). Now you need to play with the settings to achieve what you want. Adding a minimal size to visual elements usually helps to see what goes where. Otherwise, you will end up working with elements merely a pixel wide and it will be way harder. I will not address all the settings necessary but here are some useful ones.

In one of the last children, you will then need to add a "label" to hold some text. Simply drag and drop it from the ā€œControlsā€ section. Name it wisely, we will need it later. For the image, you can put a sprite in the ā€œBackgroundā€ setting of the visual element.

Tip : UI Toolkit lacks a few features including image aspect ratio lock. To do this, you can set the size to 0 and set the top padding to 100% and both side paddings to 50%. This works because the padding property is relative to the parentā€™s size when specified in percentages.

In the end, you should have something similar to this. A screenshot of the UI component hierarchy.

How to display the UI in the game ?

This step is very simple. Simply add a game object to your scene with a ā€œUI Documentā€ component. You can put your newly created UXML document in the source asset. You will also need a panel setting. You can create it from Create > UI Toolkit > Panel Settings Asset and put it in the component. Your UI should now appear in the game view. But those values need to change during runtimeā€¦ Letā€™s see how to do this!

How to update the UI content?

Create or open a script and import the UI package: using UnityEngine.UIElements;. Add a new serialized UIDocument property. We will not work with this object directly but rather with the root of the document which can be accessed using document.rootVisualElement. From this, you need to query the various elements you wish to modify. This is done using the Q<T>(string name) method which takes in the name of the element (this is where your wisely named labels will come in handy).

1Label foodLabel = root.Q<Label>("FoodLabel"); 2Label woodLabel = root.Q<Label>("WoodLabel"); 3Label stoneLabel = root.Q<Label>("StoneLabel");

Once you have accessed your elements, all there is left to do is change their text value as you would with any Unity UI Text: text.text = content;.

Save, specify your UIDocument component in the inspector and you should see the values of your brand-new UI change! Congratulations!

Thank you for reading this article to the end. In the next one, I will detail how to create a more complex UI element with dynamic UI element instantiation. I hope to see you in the next post. šŸ¦¦

Ā© Copyright 2024 - šŸ¦¦ Sea Otter Games