Home / Legacy / Lesson 11: The UI Manager (Unity 3d GUI)

Lesson 11: The UI Manager (Unity 3d GUI)

/
/
/
2152 Views
This entry is part 14 of 15 in the series Unity 3d Fundamentals Course

In this lesson we will create our UI manager using the Unity 3d GUI system to show all relevant information on screen.First we will create all the necessary GUI controls and the logic behind it. Then we will customize our controls using a GUISkin and GUIStyles.

Despite not being a supporter of the Unity 3d GUI system with all its performance related issues and even cumbersome implementation, I think that every developer should know at least the basics. Unfortunately I am not already working with the Unity 4.6 and the new GUI system, but I intend to make a future post migrating this manager to the new system.

Lesson Outline

Create the UI controls

Our UI will have three different states: (all of them very simple as you are about to see)

  • Initial – text instruction;

Lesson 11: The UI Manager (Unity 3d GUI)

  • Game – simple timer;

Lesson 11: The UI Manager (Unity 3d GUI)

  • Statistics – game statistics.

Lesson 11: The UI Manager (Unity 3d GUI)

In addition to these states we also need the pause menu.

Lesson 11: The UI Manager (Unity 3d GUI)

Now the logic behind it. At any given time in the game the UI will be in one of the three mentioned states. It will be in the Initial mode until the player enters the first beacon. In the Game mode until all targets are destroyed. And in the Statistics mode after all targets are destroyed and until the Player restarts the game.

The pause menu can appear at any time during the game so its separated or shared (in the Statistics) with the UI states.

OnGUI

Lets start with the UI States. First create a new script called UIManager.cs and add the following method OnGUI.

The OnGUI is responsible for everything related with the Unity 3d GUI system. The main aspect you need to understand when working with it, is that it runs in loop, quite similar to the Update funtion (but it may run several times per frame).

So when managing the GUI state we need to remember that everything is constantly being redrawn. So it makes impossible to easily call methods like “ShowControlA” or “HideControlB”. I mean you can call them but you need some sort of control variable to change the GUI state at runtime.

In this case since we have three different states lets create an enum to control the GUI behaviour.

Make the enum public so you can easily change its value on the inspector when testing your GUI.

Now we need to create a switch statement to change the GUI at runtime.

I think this is the easiest way to manage the OnGUI state. Now we can focus on each GUI section and add the necessary controls.

Initial State

In this one we only need a label to hold the text instruction. We will use the GUI.Label control.

static void Label(Rect position, string text);

  • returns void;
  • Rect position – The position of the label on the screen defined by a Rect;
  • string text – the text to display.

So this method returns nothing, requires only the string to show and a Rect for positioning.

The Rect object is used to define all GUI controls and it takes four parameters all given in PIXELS.

Rect(float left, float top, float width, float height);

  • float left (x);
  • float top (y);
  • float width;
  • float height;

1_5

So to create any GUI control we need to define where it starts – its top-left point – and its size – width & height.

The controls are positioned according to the Unity Screen coordinate system (it also has the Viewport and the World coordinate systems, more on this later).

Lesson 11: The UI Manager (Unity 3d GUI)

Lets create a public variable to hold the instruction.

And in the Initial state lets add a new GUI.Label with the necessary parameters.

Now you may be wondering why am I using these strange numbers to define the Rect. Well this is a simple way (maybe not the best one, I know of some more advanced ways but I think it is out of topic in these series) to make our GUI dynamically adjust itself to the current screen. I intend to build this game on Standalone and Web and I am not sure about the resolution where it will run.

So instead of using hardcoded dimensions like 100px I always prefer to work with a percentage of the screen resolution. You can access the current screen dimensions using the Screen.width and Screen.height.

In this case you can see that my Label will start near the top-left of the screen, extend its width by more than half and has a very small height.

Lesson 11: The UI Manager (Unity 3d GUI)

As I said before we will first focus on building all the controls and then on the second phase we will customize their look.

 Game State

When in the Game State we want to show a small timer near the top of the screen. Before creating the timer control we need to switch the UI state from Inital to Game. This will happen when the Player enters the first beacon. We already have that information on the Game Manager (it is important to maintain all communication with the UI Manager through the only Game Manager).

First lets create a new public method on the UI Manager and change the state to Game.

On the Game Manager lets create a public reference to the UI Manager.

And then call the method when the Player enters the beacon.

Now on the UI Manager side we need a variable to hold the timer value.

The timer will start counting as soon as we enter the Game State and will continue until we change to another one. To be constantly updating the timer we will use the Update method to increment its value by each second.

Now we need to show this value on screen so lets create a new GUI.Label but this time inside the Game State block.

Lesson 11: The UI Manager (Unity 3d GUI)

Now it is working but not with the look we want. We need to format the string in order to show the timer value exactly as we want.

Create a new reference to hold the timer value as text.

Let’s create a new method to return the timer value as a nicely formatted string.

First we need to get the minutes and the seconds as separate values. Use the Mathf.FloorToInt to round the float values to integers.

Then we need to get a string formatted as a clock: “00:00”. We will use the string.Format.

Assign the value to our new string and add it to the GUI.Label.

Now that the clock is nicely formatted we will add a clock texture right next to it. Download the following texture or use your own. [wpdm_file id=4]

We can use more than on content on a GUI control by using a GUIContent.

GUIContent(string text, Texture image);

The GUIContent supports text, image and a tooltip.

So instead of using directly a string on the GUI.Label we will create a new GUIContent with the instruction text and the timer image. Create a public reference to hold the image.

Change the GUILabel content to a new GUIContent with both elements.

Lesson 11: The UI Manager (Unity 3d GUI)

Statistics State

On the Statistics screen we will show the elapsed time and the player accuracy (ratio between the shots fired and the targets destroyed). We need to change the GUI state to the Statistics mode and provide the necessary data. All this will come from the Game Manager. First lets create the accuracy variable on the UI side (we already have the timer variables).

Now we need a public method to be called from the Game Manager with the necessary variables. On this method we will change the GUI State, assign the new timer value and the accuracy value.

All done on the UI side. Lets call this method from the Game Manager.

The Unity 3d GUI has two different Layout modes. Until now we’ve been using the Fixed Layout to create the GUI controls. But there is also the Automatic Layout. The Automatic Layout is great when you don’t know how many controls you will have – for example in a savegames list – or when you don’t want to manually position all the GUI controls by yourself.

To create the statistics screen we will use the Automatic Layout mode. To use the Automatic GUI Layout we call GUILayout instead of GUI.

The main difference when implementing this kind of Layout is that instead of positioning each GUI control we create GUI Areas on our screen and then fill them with the controls we want. Each individual control doesn’t need a Rect, only the GUI Area.

So let’s start by creating a new GUILayout Area for our Statistics. When create a new GUI Area you need to always Begin and End the Area. All the GUI controls for that area will be between both statements.

 

Since we are using a GUILayout we can just add all the controls we want inside the area. Lets add a title for our area, the time and accuracy values and another label for each value (we will separate this second label from the value because we will customize it individually).

Lesson 11: The UI Manager (Unity 3d GUI)

This is not exactly what we need. We want each value to be in front of the label and not beneath it. When adding GUI controls inside an Area it will just add them vertically one after the other. So if we want to display the contents on a different orientation we can create subgroups inside the Area: GUILayout.BeginHorizontal and GUILayout.BeginVertical.

In this case lets create a Horizontal group for each label-value pair.

Lesson 11: The UI Manager (Unity 3d GUI)

Now the controls are correctly aligned and we will later customize their looks.

Menu

The last piece of our UI is the Pause screen. This screen is independent from the GUI states since it can be called at anytime during the game. So the first thing we need is a control variable to know when to show the screen.

Lets add this verification on the OnGUI method right at the beginning and before the switch statement.

The Pause screen will use two different textures: the background texture (to darken the screen) and the logo texture. Download the textures or use your own. [wpdm_file id=5] [wpdm_file id=6]

Create the public references to these textures.

To draw textures on the GUI we use the GUI.DrawTexture method.

static void DrawTexture(Rect position, Texture image, ScaleMode scaleMode = ScaleMode.StretchToFill, bool alphaBlend = true, float imageAspect = 0);

  • returns void;
  • Rect position – the image rect;
  • Texture image – the image;
  • ScaleMode scaleMode – the scale mode defines how the texture adjusts to the rect;
  • bool alphaBlend – leave the default;
  • float imageAspect – leave the default.

Draw the texture on the GUI.

The controls order does matter when working with the OnGUI. The controls are added on top of each other. So in this case the background texture should be the first control to be drawn or it will cover the other elements.

The background texture will fill the entire screen so create the rect and choose the ScaleMode.StrecthToFill to stretch the image to fill the rect.

The logo texture will be drawn on the screen top center with a ScaleMode.ScaleToFit. This scale mode scales the texture to the rect size without messing with the image ratio. The remaining mode is the ScaleMode.ScaleAndCrop. This maintains the image ratio but it scales the image until filling the rect area and cropping the image if necessary.

To draw the menu buttons we will use the GUILayout to easily position all elements.

Lesson 11: The UI Manager (Unity 3d GUI)Now that we have the Pause screen ready we need to know when to show it. First lets create a public method to change the control variable.

This method will be called by the Game Pause Manager (it should pass through the Game Manager but as I said before this manager is not correctly implemented, I will fix it later).

Create a public reference for the UI Manager on the Game Pause Manager and call this method when changing the game state.

 

Now the only GUI controls that should appear with the Pause Mode is the Statistics screen. Lets create these verifications.

To finish we need to set the game in Pause Mode when we reach the Statistics state. The Game Manager should tell the Game Pause Manager to pause just before changing to the Statistics screen.

Now all the logic is ready and the screens are being shown correctly. On the next phase we will learn how to customize them.

Customize the UI

To customize the GUI we need a GUISkin object.

The GUISkin defines how each GUI control will look and behave. It contains GUI settings and a collection of GUIStyle objects that together specify GUI skin.

First create a new GUISkin object.

Lesson 11: The UI Manager (Unity 3d GUI)

To apply the GUISkin to the UI  Manager you need a public reference.

And then apply the skin inside the OnGUI method – it should be the first thing to make inside the OnGUI.

Now that we have a custom skin applied to our GUI we can adjust its properties.

Lesson 11: The UI Manager (Unity 3d GUI)

The first thing we will change its the main font used by our GUI. By default the GUI uses the Arial font but we will change it. Download the following fonts: [wpdm_file id=7] [wpdm_file id=8]

We wil use the Langdon as the main font for our GUI. We can change the default font used by all controls on Font entry in the GUISkin panel.

Lesson 11: The UI Manager (Unity 3d GUI)

Now all controls will use this font by default.

Lesson 11: The UI Manager (Unity 3d GUI)

However we want to customize the intruction label a little more. Maybe center the text on the label and increase the font size. Lets create a custom style to apply to the instruction label only. Each style has its own properties and can be applied to any control we want.

Lesson 11: The UI Manager (Unity 3d GUI)

Instructions label

Apply the following changes:

  • Increase the font size;
  • Change the alignment to Middle Center (this will position the text inside the Label rect);
  • Change the Normal Text Color to White (this is the color of the font when on normal mode, you can customize it to hover and pressed also for example).

Lesson 11: The UI Manager (Unity 3d GUI)

Now we need to tell the instruction label to use this style instead of the default label style using the skin.GetStyle(“Style Name”).

After assigning the Style to the control you can adjust the style properties on Play Mode while seeing automatically the changes you are performing.

Timer Label

Now that we know how to create and apply custom styles, let’s create a new style for the Timer Label and change the following properties:

  • Normal Text Color;
  • Font to LiquidCrystal-Bold;
  • Font size to 29;
  • Alignment to Middle Center;
  • Image Position to Image Above or Image Left as you prefer (this controls the relative positioning of the image and text when both are present, you can also restrict the style on only one of them).

Lesson 11: The UI Manager (Unity 3d GUI)

Apply the style to the Timer Label.

Now we need to customize the Statistics Screen. We create the following styles: Title; Label; Value and apply them to each control.

Check the following page for a detailed description of each GUIStyle property: UNITY GUI STYLES.

When creating a new style it will copy the configuration of the last one. Pay attention to that and think if you should create all styles first or if some will share the customization you should customize first and then create a new one to automatically have that configuration.

Statistics Title

  • Normal Text Color to Red;
  • Margin Bottom to 15 (the Margins sets the minimum distance the other control will have from this one);
  • Font to none (so it uses the main font we defined earlier);
  • Font size to 29;
  • Alignment to Middle Center;
  • Stretch Width to true (when using the GUILayout the controls adjust by default to their content. So if we want to center the title on the area we need to make it stretch to the area where it is contained).

Lesson 11: The UI Manager (Unity 3d GUI)

Statistics Label

  • Normal Text Color to White;
  • Padding Bottom to 25 (the Padding sets the distance between the control edge and the contents);
  • Font to none (so it uses the main font we defined earlier);
  • Font size to 29;
  • Alignment to Middle Left;
  • Stretch Width to true (when using the GUILayout the controls adjust by default to their content. So if we want to center the title on the area we need to make it stretch to the area where it is contained).

Lesson 11: The UI Manager (Unity 3d GUI)

Statistics Value

  • Normal Text Color to Yellow;
  • Padding Bottom to 25;
  • Font to none (so it uses the main font we defined earlier);
  • Font size to 35;
  • Alignment to Middle Right;
  • Stretch Width to true (when using the GUILayout the controls adjust by default to their content. So if we want to center the title on the area we need to make it stretch to the area where it is contained).

Lesson 11: The UI Manager (Unity 3d GUI)

Menu

When customizing GUI buttons it is important to apply different images to each button state: Normal, Hover and Pressed. Download the following images: [wpdm_file id=9] [wpdm_file id=10] [wpdm_file id=11]

In this case since all buttons on our GUI will be the same we can adjust the Default Button style:

  • Assign each image to the respective button state;
  • Adjust the border to 4 (the Border property defines which portion of the image is not affected by the scale of the control, more on this on a following lesson);

If you are using your own images for the buttons and they are not prepared to work with the Border property just put all borders to zero

  • Adjust the Margin and Padding;
  • Font size to 32;
  • Stretch Width and Height so that the buttons fill the entire GUILayout.Area rect.

Lesson 11: The UI Manager (Unity 3d GUI)

To finish just add the StatisticsTitle style to the menu title.

The UI is all customized but I’ll leave it to you to make it look good.

Lesson 11: The UI Manager (Unity 3d GUI)

Full Codes

<UIManager.cs>

 <GameManager.cs>

Names to Keep

What’s next…

On the next we will create the Main Menu and implement scenes navigation.

Series Navigation<< Lesson 10: The Game ManagerLesson 12: The Main Menu >>
  • Facebook
  • Twitter
  • Google+
  • Linkedin
  • Pinterest
  • Reddit

Leave a Comment

Your email address will not be published. Required fields are marked *