GUI Scripting in Unity

Unity GUI

Unity GUI

In this article I will introduce the reader to Graphical User Interface (GUI) scripting in Unity. Unity has a very powerful GUI scripting Application Programming Interface (API). It allows you to quickly create simple menus and GUIs using scripts.

Introduction

Unity provides the ability to create GUI interfaces through the use of scripts. At the time of this writing, Unity does not provide a native visual GUI development tool, although you can probably find some tools on the Unity Asset Store that can be used to create GUIs using some form of visual scripting. Autodesk Scaleform also provides a plugin that can be purchased seperatly and integrated into Unity but this is beyond the scope of this article. If you are interested in the Scaleform plugin for Unity, I recommend you see Scaleform Unity Plugin.

Unity provides two primary classes for creating GUIs. The GUI class is used to create GUI controls using manual positioning. The GUILayout class is used to create GUI controls using automatica positioning. The difference between these two classes will be made clear later in the article.

Unity also provides the GUISkin asset that can be used to apply a common “look and feel” to your GUI controls. A GUISkin is simply a collection of GUIStyle objects. Each GUIStyle object defines the style of a single GUI control, such as a button, a label, or a text area.

The GUIText component can be used to render a single text element and a GUITexture component can be used to render 2D textures to the screen. Both the GUIText and the GUITexture components are suitable for drawing GUI elements (like the Heads-Up Display (HUD)) for your game, but these components are not suitable for drawing in-game menus. For in-game menus (like a level select screen or the options settings screen) you should use the GUI and GUILayout classes.

Each of these different classes, assets and components will be described throughout this article.

Creating Menus

I will first describe how to create menus in Unity using the GUI and the GUILayout classes. I will also show you how to customize the look and feel of your GUI controls by using the GUISkin and GUIStyle objects.

The OnGUI Callback Function

GUI rendering is performed by creating a script and defining a function called OnGUI. All GUI rendering should be performed in this function or in a function that is called by the OnGUI function.

function OnGUI()
{
    var buttonWidth = 100;
    var buttonHeight = 50;
    
    var buttonX = ( Screen.width - buttonWidth ) / 2.0f;
    var buttonY = ( Screen.height - buttonHeight ) / 2.0f;

    // Draw a button control in the center of the screen.
    if ( GUI.Button( Rect( buttonX, buttonY, buttonWidth, buttonHeight ), "Press Me!" ) )
    {
        // Print some text to the debug console
        Debug.Log("Thanks!");
    }
}

The ButtonDemo.js script will draw a button in the center of the screen. If the button is released, the text “Thanks!” will be printed to the debug console.

Unity Buttons

Button Demo

GUIContent

Most of the common GUI controls such as buttons and labels allow you to specify the text or the texture that should appear on the control. If you want to specify both text and a texture on a GUI control you must use a GUIContent structure.

The GUIContent structure has several constructors that allow you to create a GUIContent object with text, a texture, and a tooltip.

The following example expands on the previous example, but in this case the content for the button is specified using a GUIContent structure.

#pragma strict

var texture : Texture;
var text : String;
var tooltip : String;

function OnGUI()
{
    var buttonWidth = 100;
    var buttonHeight = 50;
    
    var buttonX = ( Screen.width - buttonWidth ) / 2.0f;
    var buttonY = ( Screen.height - buttonHeight ) / 2.0f;
    
    // Draw a button with text and an image in the center of the screen.
    if ( GUI.Button( Rect( buttonX, buttonY, buttonWidth, buttonHeight ),
                     GUIContent( text, texture, tooltip ) ) )
    {
        // Print some text to the debug console
        Debug.Log("Thanks!");
    }
}

The revised ButtonDemo.js script file will display a button on the screen with text and a texture. The texture, text, and tooltip parameters can be specified in the inspector.

The ButtonDemo.js script should produce the following result:

GUIContent Example

GUIContent Example

Positioning Controls

Using the GUI class you must manually position the controls on the screen. Controls are positioned using the position parameter of any of the GUI static functions. In order to position the controls on the screen, you must pass a Rect structure as the first parameter to the GUI control functions. The properties of the Rect structure define the X, Y, Width, and Height values for the control. The X, Y, Width, and Height of the Rect structure are all expressed in screen pixels.

Unity Screen Coordinates

Unity Screen Coordinates

The Screen.width and Screen.height properties can be used to query the current screen dimensions.

The ScreenDimensions.js script can be used to render the screenshot above:

function OnGUI()
{
    var width = Screen.width;
    var height = Screen.height;

    GUI.Label( Rect(0, 0, 100, 20), "Top Left" );
    GUI.Label( Rect(width-100, 0, 100, 20), "Top Right");
    GUI.Label( Rect(0, height-20, 100, 20), "Bottom Left");
    GUI.Label( Rect(width-100, height-20, 100, 20), "Bottom Right");
}

The ScreenDimension.js script will draw four labels. Each label is aligned to the corners of the screen using the Screen.width and Screen.height properties to determine their screen positions (measured in screen pixels).

The GUI Class

The GUI Class is the main class used in Unity for rendering GUI controls on the screen. The GUI class uses manual positioning to determine the position of the controls on the screen. This means that you must explicitly specify the screen position of the controls when you render them. Manually positioning controls using this method is more work but it gives you more precise control over the position of the controls on the screen. If you don’t want to manually specify the position of the GUI controls, then you should use the GUILayout class instead. The GUILayout class will be described in more detail later.

GUI Controls

In the following sections, I will describe the different controls that you have access to using either the GUI or GUILayout classes. The default controls that these classes provide are box, button, label, window, texture, scroll bars, sliders, text field, text area, toggle, and toolbar.

GUI.Button

One of the most common controls you will probably use is the button control. You can create a button using the GUI.Button() static function. This function is used to render a button on the screen. This function will return true when the button is released.

It is interesting to note that the GUI.Button function will only return true if the mouse is pressed and released over the button. If the user presses the button, but then moves the mouse off the button and releases the mouse, then this function will not return true. Also, if the user clicks the mouse then moves the mouse cursor over the button and then releases the mouse will also not cause this function to return true. The mouse must be pressed and released over the button for this function to return true.

The following script can be used to create a simple level select screen using buttons (assuming you have multiple scene files setup in the Build Settings dialog).

function OnGUI()
{
    var groupWidth = 120;
    var groupHeight = 150;
    
    var screenWidth = Screen.width;
    var screenHeight = Screen.height;
    
    var groupX = ( screenWidth - groupWidth ) / 2;
    var groupY = ( screenHeight - groupHeight ) / 2;
    
    GUI.BeginGroup( Rect( groupX, groupY, groupWidth, groupHeight ) );
    GUI.Box( Rect( 0, 0, groupWidth, groupHeight ), "Level Select" );
    
    if ( GUI.Button( Rect( 10, 30, 100, 30 ), "Level 1" ) )
    {
        Application.LoadLevel(1);
    }
    if ( GUI.Button( Rect( 10, 70, 100, 30 ), "Level 2" ) )
    {
        Application.LoadLevel(2);
    }
    if ( GUI.Button( Rect( 10, 110, 100, 30 ), "Level 3" ) )
    {
        Application.LoadLevel(3);
    }
    
    GUI.EndGroup();
}

Adding the script to an empty scene should result in the following:

Unity - Level Select

Unity – Level Select

You may also want to look at GUI.Toggle and GUI.RepeatButton in the Unity Scripting reference which are similar to the GUI.Button control but have slightly different functionality.

GUI.Label

The GUI.Label() static function is used to draw a label. A label is usually simply a text string that is drawn on the screen at a specific position. The most common use of the Label control is to name options in a menu screen (such as a text box or a text area).

Labels can contain text, textures, or both a text and texture (using a GUIContent structure described earlier).

The following example shows two options being drawn on the screen. The option names and the values of the sliders are drawn with labels.

#pragma strict

private var masterVolume : float = 1.0;
private var sfxVolume : float = 1.0;

function OnGUI()
{
    var groupWidth = 380;
    var groupHeight = 110;
    
    var screenWidth = Screen.width;
    var screenHeight = Screen.height;
    
    var groupX = ( screenWidth - groupWidth ) / 2;
    var groupY = ( screenHeight - groupHeight ) / 2;
    
    GUI.BeginGroup( Rect( groupX, groupY, groupWidth, groupHeight ) );
    GUI.Box( Rect( 0, 0, groupWidth, groupHeight ), "Audio Settings" );
    
    GUI.Label( Rect( 10, 30, 100, 30 ), "Master Volume" );
    masterVolume = GUI.HorizontalSlider( Rect( 120, 35, 200, 30 ), masterVolume, 0.0, 1.0 );
    GUI.Label( Rect( 330, 30, 50, 30 ), "(" + masterVolume.ToString("f2") + ")");

    GUI.Label( Rect( 10, 70, 100, 30 ), "Effect Volume" );
    sfxVolume = GUI.HorizontalSlider( Rect( 120, 75, 200, 30 ), sfxVolume, 0.0, 1.0 );
    GUI.Label( Rect( 330, 70, 50, 30 ), "(" + sfxVolume.ToString("f2") + ")");

    GUI.EndGroup(); 
}

The OptionsMenu.js script should result in the following screen:

Unity - Labels Example

Unity – Labels Example

You should also look at GUI.TextField and GUI.TextArea which are controls that allow you to create editable text input controls.

GUI.HorizontalSlider and GUI.VerticalSlider

The GUI.HorizontalSlider and GUI.VerticalSlider static functions can be used to draw horizontal and vertical sliders respectively. A slider is used to specify a number within a certain range. In the example above, two horizontal sliders were used to specify the values for the master volume and sound effects volume in the range 0 to 1.

The slider functions take the current value of the slider and the min and max values of the slider. The example above shows how to use a horizontal slider, but a vertical slider uses exactly the same parameters except the slider is drawn vertically instead of horizontally.

The following example demonstrates the use of vertical sliders to create a audio equalizer.

#pragma strict

private var equalizerValues = new float[10];

function OnGUI() 
{
    var groupWidth = 320;
    var groupHeight = 260;
    
    var screenWidth = Screen.width;
    var screenHeight = Screen.height;
    
    var groupX = ( screenWidth - groupWidth ) / 2;
    var groupY = ( screenHeight - groupHeight ) / 2;
    
    GUI.BeginGroup( Rect( groupX, groupY, groupWidth, groupHeight ) );
    GUI.Box( Rect( 0, 0, groupWidth, groupHeight ), "Equalizer" );

    for( var i = 0; i < equalizerValues.Length; ++i )
    {
        equalizerValues[i] = GUI.VerticalSlider( Rect( ( i * 30 ) + 20, 30, 20, 200), equalizerValues[i], 0.0, 1.0 );
    }

    GUI.EndGroup();
}

The resulting GUI should look something like this:

Unity - Vertical Scroll Bars

Unity – Vertical Scroll Bars

When using horizontal sliders, the minimum value is at the left of the slider and the maximum at the right. When using vertical sliders, the minimum value is at the top and the maximum value is at the bottom of the slider.

You may want to also look at GUI.HorizontalScrollbar and GUI.VerticalScrollbar which are similar to sliders but have different functionality.

GUI.Window and GUI.DragWindow

The GUI class provides functions for drawing windows on the screen. A window uses an external function (other than OnGUI) to render the contents of that window.

If the GUI.DragWindow function is used inside the window’s callback function, that window will be draggable.

The following script creates a simple window that can be dragged:

#pragma strict

// The initial position and size of the window.
private var windowRect0 = Rect( 20, 20, 150, 0 );

function OnGUI () 
{
	// Render the window with ID 0.
	windowRect0 = GUILayout.Window( 0, windowRect0, WindowFunction, "Draggable Window" );	
}

// Window 0's callback function
function WindowFunction()
{
	GUILayout.Label( "This is a draggable window!" );
	
	// The drag-strip for the window. 
	// Coordinates are relative to the top-left of the window.
	GUI.DragWindow( Rect( 0, 0, 150, 20 ) );
}

If you apply the DraggableWindow.js script to a GameObject in a new scene, you should see the window and you should be able to move the window around the screen by clicking and dragging on the window title.

Unity - Draggable Window

Unity – Draggable Window

You can place any number of controls inside a window. If you want to have Unity automatically layout the controls in a Window (as shown in this example) then you should also use the GUILayout.Window function instead of the GUI.Window function. When using the GUILayout.Window function, Unity will automatically modify the height of the window to fit it’s contents. As shown in the example above.

Automatic Layout

In most of the examples shown here, I was using the GUI class to create the menus. The GUI class requires that we manually position the controls on the screen. In some cases, manually positioning controls is useful, but if you want Unity to automatically layout the controls for you, then you should use the GUILayout class instead. The GUILayout class provides a lot of the same functionality as the GUI class but does not require you to specify the dimensions of the controls.

GUILayout.BeginHorizontal and GUILayout.BeginVertical

By default, all controls will be placed in the view in vertical order when using GUILayout functions. You can change the order in which controls are placed next to each other by using the GUILayout.BeginHorizontal() and GUILayout.BeginVertical() static functions. Every occurrence of GUILayout.BeginVertical must have a matching GUILayout.EndVertical and every occurrence of GUILayout.BeginHorizontal must have a matching GUILayout.EndHorizontal.

The following example shows how you can use vertical and horizontal layouts to create complex forms.

#pragma strict

private var firstName : String = "First Name";
private var lastName : String = "Last Name";
private var age : uint = 0;
private var submitted : boolean = false;

private var windowRect0 : Rect;

function Start()
{
}

function OnGUI()
{
    var screenWidth = Screen.width;
    var screenHeight = Screen.height;
    
    var windowWidth = 300;
    var windowHeight = 180;
    var windowX = ( screenWidth - windowWidth ) / 2;
    var windowY = ( screenHeight - windowHeight ) / 2;
    
    // Postion the window in the center of the screen.
    windowRect0 = Rect( windowX, windowY, windowWidth, windowHeight );

    GUILayout.Window( 0, windowRect0, UserForm, "User Information" );
}

function UserForm()
{
    GUILayout.BeginVertical();
    
    // First Name
    GUILayout.BeginHorizontal();
    GUILayout.Label("First Name", GUILayout.Width(80));
    firstName = GUILayout.TextField( firstName );
    GUILayout.EndHorizontal();
    
    // Last Name
    GUILayout.BeginHorizontal();
    GUILayout.Label("Last Name", GUILayout.Width(80));
    lastName = GUILayout.TextField( lastName );
    GUILayout.EndHorizontal();
    
    // Age
    GUILayout.BeginHorizontal();
    GUILayout.Label("Age", GUILayout.Width(80));
    var ageText = GUILayout.TextField( age.ToString() );
    var newAge = age;
    if ( uint.TryParse( ageText, newAge ) )
    {
        age = newAge;
    }
    GUILayout.EndHorizontal();
    
    if ( GUILayout.Button( "Submit" ) )
    {
        submitted = true;
    }
    if ( GUILayout.Button( "Reset" ) )
    {
        firstName = "First Name";
        lastName = "Last Name";
        age = 0;
        submitted = false;
    }
    
    if ( submitted )
    {
        GUILayout.Label("Submitted!");
    }
    
    GUILayout.EndVertical();
}

This may appear to be a complicated script. There are a few things here that may seem unfamiliar if you are not familiar with scripting. The important thing to note is that I use a static window (not draggable) to group the controls. The window needs to have a function that is used to draw it’s internals. For this, I use the UserForm function.

The user form starts with a vertical layout. Since the vertical layout is the default layout when using automatic layouts, specifying this explicitly is optional.

Then each field is created in a horizontal layout with the label followed by a text field. The label is explicitly sized to 80 pixels using the GUILayout.Width() function. I do this to ensure all of the text fields are nicely aligned. The text fields will be expanded to fill the remaining area of the window.

After the text fields, two buttons are added in vertical layout. The buttons will expand to fill the area and their height will be determined by the content of the button.

Don’t forget to always end a vertical or horizontal layout using the GUILayout.EndVertical() or GUILayout.EndHorizontal() functions.

The UserForm.js script should produce the following result:

Unity - Layout Example

Unity – Layout Example

You may also want to look at GUI.BeginGroup, GUILayout.BeginArea, and GUI.BeginScrollView. All of these functions can be used to create a group (or area in the case of automatic layouts) that can be used to keep controls grouped in a particular area.

Styles and Skins

Unity provides a default “look and feel” for all of the GUI controls. For a quick solution, the default style may be sufficient for your needs but you probably don’t want to ship your production game using Unity’s default GUI styles.

GUISkin

Using a custom GUISkin you can modify the appearance of the buttons, labels, sliders, and scrollbars, etc.

The GUISkin is an asset that you can create by selecting Assets > Create > GUISkin from the main menu.

Unity - GUISkin

Unity – GUISkin

If you select the GUISkin asset in the project view, you can edit the individual GUIStyle settings for the various controls that you can create.

To override the default skin with your own custom skin, set the GUI.skin property to your custom skin anywhere in your GUI script. Setting the GUI.skin property to null will restore the default GUISkin.

GUIStyle

A GUISKin is simply a collection of GUIStyle objects. A GUIStyle defines the styles for the various states a control can have. A control can have the following states:

  • Normal: The control is in it’s default state. The mouse is no hovering over the control nor does the control have focus.
  • Hover: The mouse is currently over the control.
  • Focused: The control is the currently selected control. The focused control will receive keyboard input. This state is valid for buttons and editable text controls.
  • Active: The control is being pressed. This state is valid for buttons, sliders and scroll bars.

A GUIStyle can be used without a GUISkin in order to override the style of that control. To use a GUIStyle, simply create a public variable in your GUI script of type GUIStyle and specify the style’s settings in the inspector. When you want to apply the style to a control, just pass the style as the final parameter to the control function.

As an exercise, download the following Unity package and import it into a new Unity project:

GUIStylesExample.unitypackage

Create a new script called LevelSelect.js with the following content:

#pragma strict

var buttonStyle : GUIStyle;

function OnGUI()
{
    var groupWidth = 120;
    var groupHeight = 150;
    
    var screenWidth = Screen.width;
    var screenHeight = Screen.height;
    
    var groupX = ( screenWidth - groupWidth ) / 2;
    var groupY = ( screenHeight - groupHeight ) / 2;
    
    GUI.BeginGroup( Rect( groupX, groupY, groupWidth, groupHeight ) );
    GUI.Box( Rect( 0, 0, groupWidth, groupHeight ), "Level Select" );
    
    if ( GUI.Button( Rect( 10, 30, 100, 30 ), "Level 1", buttonStyle ) )
    {
        Application.LoadLevel(1);
    }
    if ( GUI.Button( Rect( 10, 70, 100, 30 ), "Level 2", buttonStyle ) )
    {
        Application.LoadLevel(2);
    }
    if ( GUI.Button( Rect( 10, 110, 100, 30 ), "Level 3", buttonStyle ) )
    {
        Application.LoadLevel(3);
    }
    
    GUI.EndGroup();
}

You may have noticed that this is the same code as the button example but now we are applying a custom style to the buttons.

In the inspector, set the following options on the Button Style property:

  • Normal.Background: roundedButton_Normal.psd
  • Normal.Text Color: (0, 0, 0, 255)
  • Hover.Background: roundedButton_Hover.psd
  • Hover.Text Color: (0, 0, 0, 255)
  • Active.Background: roundedButton_Active.psd
  • Active.Text Color: (80, 80, 255, 255)
  • Border.Left: 6
  • Border.Right: 6
  • Border.Top: 6
  • Border.Bottom: 6
  • Padding.Left: 6
  • Padding.Right: 6
  • Padding.Top: 12
  • Padding.Bottom: 6
  • Font: SHOWG
  • Alignment: Middle Center

You should get something similar to what is shown below:

Unity - Custom Styles

Unity – Custom Styles

Demo

The following is an interactive demo that shows how to use various controls. The demo contains the following scenes:

  • GUI Basics: Describes the OnGUI function and shows an example of using a button and box control.
  • Controls: This scene shows the various controls that you can create.
  • Customization: How to create skins and styles.
  • Layout: Describes fixed and and automatic layout modes. Also shows an example of using vertical and horizontal layouts.
  • Extending the Unity Editor: This scene shows an example of how you can create custom editor windows in Unity. Download the Unity project and load it into Unity to see the custom editor window.

Launch Demo

Download Demo

Download and extract the zip file. Open the Assets/Scenes/Introduction.unity scene file in the Unity editor.

10 thoughts on “GUI Scripting in Unity

  1. This is an excellent write-up. I really loved all the side notes about checking out this or that piece of the GUI for extended learning. This has probably save between 5-8 hours of investigation, testings and error. Thanks!

Leave a Reply

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