Everything that is shown on the screen and transmits through the speakers of a computer is forms of communication. In previous chapters, we used three-dimensional models to let the user know that they are in a base in the middle of the mountains, and we reinforced that idea with the appropriate sound and music. But for our game, we need to communicate other information, such as the amount of life the user has left, the current score, and so on, and sometimes, it is difficult to express these things using the in-game graphics (there are some successful cases that manage to do this, such as Dead Space, but let's keep things simple). In order to transmit this information, we will add another layer of graphics on top of our scene, which is usually called the User Interface (UI) or Heads-Up Display (HUD).
This will contain different visual elements, such as text fields, bars, and buttons, to prepare the user to take an informed decision based on things such as fleeing to a safe place when their life is low:
In this chapter, we will examine the following UI concepts:
By the end of this chapter, you will be able to use the Unity UI system to create interfaces capable of informing the user about the state of the game and allowing them to take action by pressing buttons. Let's start discussing one of the basic concepts of the Unity UI system—RectTransform.
Currently, there are three UI systems available in Unity for different purposes:
In this chapter, we are only going to focus on in-game UI to communicate different information to the player regarding the state of the game, so we are going to use Unity UI. At the time of writing this book, there are plans to replace Unity UI with UI Elements, but there's no estimated date as to when this will happen. Anyway, even if Unity releases UI Elements as an in-game UI system soon, Unity UI will still be there for a while and is perfectly capable of handling all types of UI that you need to create.
If you are going to work with Unity UI, you first need to understand its two main concepts—Canvas and RectTransform. Canvas is the master object that will contain and render our UI and RectTransform is the feature in charge of positioning and adapting each UI element on our screen.
In this section, we will examine the following Unity UI concepts:
Let's start using the Canvas component to create our UI.
In Unity UI, each image, text, and element you see in the UI is a GameObject with a set of proper components, but in order for them to work, they must be a child of a master GameObject with the Canvas component. This component is responsible for triggering the UI generation and drawing iterations over each child object. We can configure this component to specify exactly how that process works and adapt it to different possible requirements.
To start, you can simply create a canvas with the GameObject | UI | Canvas option. After doing that, you will see a rectangle in the scene, which represents the user screen, so you can put elements inside it and preview where they will be located relative to the user's monitor. You can see an example of this rectangle in the following screenshot:
You are probably wondering two things here. First, "why is the rectangle is in the middle of the scene? I want it to always be on the screen!". Don't worry because that will exactly be the case. When you edit the UI, you will see it as part of the level, as an object inside it, but when you play the game, it will be always projected over the screen, on top of every object. Also, you may be wondering why the rectangle is huge, and that's because one pixel of the screen maps to one meter on the scene. So again, don't worry about that; you will see all your UI elements in their proper size and position on the user's screen when you see the game in Game view.
Before adding elements to our UI, it's worth noting that when you created the UI, a second object is created alongside the canvas, called Event System. This object is not necessary to render a UI, but is necessary if you want the UI to be interactable, which means including actions such as clicking buttons, introducing text in fields, or navigating the UI with the joystick. The EventSystem component is responsible for sampling the user input, such as with a keyboard, mouse, or joystick, and sending that data to the UI to react accordingly. We can change the exact buttons to interact with the UI, but the defaults are OK for now, so just know that you need this object if you want to interact with the UI. If for some reason you delete the object, you can recreate it again in GameObject | UI | Event System.
Now that we have the base objects to create our UI, let's add elements to it.
In Unity UI, each image, text, and element you see in the UI is a GameObject with a set of proper components according to its usage, but you will see that most of them have one component in common—RectTransform. Each piece of the UI is essentially a rectangle filled with text or images and has different behavior, so it is important to understand how the RectTransform component works and how to edit it.
In order to experiment with this component, let's create and edit the position of a simple white rectangle element for the UI by doing the following:
Now that we know the very basics of how to position any UI object, let's explore the different types of elements you can add to Canvas.
So far, we have used the simplest Canvas object type—a white box—but there are plenty of other object types we can use, such as images, buttons, text, and much more. All of them use RectTransform to define their display area, but each one has its own concepts and configurations to understand.
In this section, we will explore the following Canvas object concepts:
Let's first start exploring how we can integrate images and fonts to use in our canvas so that we can integrate them in our UI using the Images and Text UI object types.
Before making our UI use nice graphics assets, we need, as always, to integrate them properly into Unity. In the following screenshot, you will find the UI design we proposed in Chapter 1, Designing a Game From Scratch:
On top of that, we will add a Pause menu, which will be activated when the user presses Esc. It will look as in the following screenshot:
Based on these designs, we can determine that we will need the following assets:
As always, we can find the required assets on the internet or on Asset Store. In my case, I will use a mixture of both. Let's start with the simplest one—the avatar. Take the following steps:
For the bars, buttons, and the window background, I will use Asset Store to look for a UI pack. In my case, I found the package in the following screenshot a good one to start my UI. As usual, remember that this exact package might not be available right now. In that case remember to look for another similar package, or pick the Sprites from the GitHub repo:
At first, the pack contains lots of images configured the same way, as sprites, but we can further modify the import settings to achieve advanced behavior, as we will need for the buttons. The button asset comes with a fixed size, but what happens if you need a bigger button? One option is to use other button assets with different sizes, but this will lead to a lot of repetitions of the buttons and other assets, such as different-sized backgrounds for different windows, which will consume unnecessary RAM. Another option is to use the nine slices method, which consists of splitting an image so that the corners are separated from the other parts. This allows Unity to stretch the middle parts of the image to fit different sizes, keeping the corners at their original size, which, when combined with a clever image, can be used to create almost any size you need. In the following diagram, you can see a shape with nine slices in the bottom-left corner, and at the bottom-right corner of the same diagram, you can see the shape is stretched but keeps its corners at their original size. The top-right corner shows the shape stretched without slices. You can see that the non-sliced version is distorted, while the sliced version is not:
In this case, we can apply the nine-slices to the button and the panel background images to use them in different parts of our game. In order to do this, do the following:
Now that we have prepared our sprites, we can find a font, which is a pretty easy task. Just download any font in the .ttf or .otf formats and import it to Unity, and that's all—no further configuration required. You can find lots of good, free font websites on the internet. I am used to working with the classic DaFont.com site, but there's plenty of other sites that you can use. In my case, I will work with the following font:
If the zipped file contains several font files, you can just drag them all into Unity and then use the one that you like the most. Also, as usual, try to put the font inside a folder called Fonts.
Now that we have all the required assets to create our UI, let's explore the different types of components to create all the required UI elements.
Almost every single part of the UI will be a combination of images and texts configured cleverly. In this section, we will explore the following components:
Let's start exploring Image. Actually, we have already an image in our UI—the white rectangle we created previously in this chapter. If you select it and look at the Inspector window, you will notice that it has an Image component, like the one in the following screenshot:
Let's start exploring the different settings of this component, starting with our hero's avatar. Take the following steps:
Now, let's create the life bars by doing the following:
Now, let's add the text fields for the Score, Bullets, Remaining Waves, and Remaining Enemies labels by doing the following:
Now that we have completed the original UI design, let's create the Pause menu by doing the following:
In the following two screenshots, you can see the background image with a Pixels Per Unit value of 100 and again with 700. Remember to only do this for the nine-slices or tiled-image types, or if you don't have an artist to adjust it for you:
As you can see, you can create almost any kind of UI just by using Image and Text components. Of course, there are more advanced components that enable you to create buttons, text fields, checkboxes, lists, and so on, but let's stick to the basics one. One thing to notice is that we have created buttons, but they do nothing so far. Later, in Part 3 of the book, we will see how to script them to have a function.
In this section, we discussed how to import images and fonts to be integrated through the Image, Text, and Button components to create a rich and informative UI. Having done that, let's discuss how to make them adapt to different devices.
Nowadays, it is almost impossible to design a UI in a single resolution, and our target audience display devices can vary a lot. A PC has a variety of different kinds of monitors with different resolutions (such as 1080p, 4k, and so on) and aspect ratios (such as 16:9, 16:10, ultra-wide, and so one), and the same goes for mobile devices. We need to prepare our UI to adapt to the most common displays, and Unity UI has the tools needed to do so.
In this section, we will explore the following UI responsiveness concepts:
We are going to explore how the UI elements can adapt their position and size to different screen sizes using advanced features of the Canvas and RectTransform components, such as Anchors and Scalers.
Right now, if we play our game, we will see how the UI fits nicely onto our screen. But if for some reason we change the Game view size, we will see how objects start to disappear from the screen. In the following screenshots, you can see different sized game windows and how the UI looks nice in one but bad in the others:
The problem is that we created the UI using whatever resolution we had in the editor, but as soon as we change it slightly, the UI keeps its design for the previous resolution. Also, if you look closely, you will notice that the UI is always centered, such as in the middle image, where the UI is cropped at its sides, or the third image, where extra space is visible along the borders of the screen. This happens because every single element in the UI has its own Anchor, a little cross you can see when you select an object, such as the one in the following screenshot:
The X and Y position of the object is measured as a distance to that Anchor, and the Anchor has a position relative to the screen, with its default position being at the center of the screen. This means that on an 800 x 600 screen, the Anchor will be placed at the 400 x 300 position, and on a 1920 x 1080 screen, the Anchor will be located at the 960 x 540 position. If the X and Y position of the element (the one in RectTransform) is 0, the object will always be at a distance of 0 from the center. In the middle screenshot of the previous three examples, the hero avatar falls outside of the screen because its distance from the center is greater than half the screen, and the current distance was calculated based on the previous, bigger screen size. So, what we can do about that? Move the Anchor!
By setting a relative position, we can position the Anchor at different parts of our screen and make that part of the screen our reference position. In the case of our hero avatar, we can place the Anchor at the top-left corner of the screen to guarantee that our avatar will be at a fixed distance from that corner. We can do that by doing the following:
Now that our UI elements have adapted to their positions, let's consider scenarios where the object size must adapt as well.
The first thing to consider when dealing with different aspect ratios is that our screen elements may not only move from their original design position (which we fixed in the previous section) but also they may not fit into the original design. In our UI, we have the case of the health bar, where the bar clearly doesn't adapt to the screen width when we previewed it on a wider screen. We can fix this by breaking our Anchors.
When we break our Anchors, the position and size of our object are calculated as a distance relative to the different Anchor parts. If we split the Anchor horizontally, instead of having an X and Width property, we will have a Left and Right property, representing the distance to the left and right Anchor. We can use this in the following way:
This way, the object will always be at a fixed distance of a relative position to the screen—in this case, the sides of the screen. If you are working with a child object, as is the case of the Text and Image components of the buttons, the Anchors are relative to the parent. If you pay attention to the Anchors of the text, they are not only split horizontally but also vertically. This allows the text to adapt its position to the size of the button, so you won't have to change it manually:
Now, this solution is not suitable for all scenarios. Let's consider a case where the hero avatar is displayed in higher resolution than what it was designed for. Even if the avatar is correctly placed, it will be displayed smaller because the screen has more pixels per inch that the other resolution. You consider using split Anchors, but the width and height Anchors could be scaled differently in different aspect ratio screens, so the original image becomes distorted. Instead, we can use the Canvas Scaler component.
The Canvas Scaler component defines what 1 pixel means in our scenario. If our UI design resolution is 1080p, but we see it in a 4k display (which is twice the resolution of 1080p), we can scale the UI so that a pixel becomes 2, adapting its size to keep the same proportional size as the original design. Basically, the idea is that if the screen is bigger, our elements should also be bigger.
We can use this component by doing the following:
You will find that your UI will be smaller than your original design, which is because we should have set these properties before. Right now, the only fix is to resize everything again. Take this into account the next time you try this exercise; we only followed this order for learning purposes.
Before moving on, remember to reactivate the postprocessing volume object to show those effects again. You will notice that the UI is not affected by them in the Game view.
Important note:
If you want your UI to be affected by postprocessing effects, you can set Canvas Render Mode to Screen Space – Camera. Drag the main camera to the Render Camera property and set Plane Distance to 5. This will put the UI in the world with the rest of the objects, aligned to the camera view with a distance of 5 meters.
With this knowledge, you are now ready to start creating your firsts UIs by yourself.
In this chapter, we introduced the basics of UI, understanding the Canvas and RectTransform components to locate objects onscreen and create a UI layout. We also covered different kinds of UI elements, mainly Image and Text, to give life to our UI layout and make it appealing to the user. Finally, we discussed how to adapt UI objects to different resolutions and aspect ratios to make our UI adapt to different screen sizes, even though we cannot predict the exact monitor our user will be playing the game on.
In the next chapter, we will start seeing how to add animated characters to our game.