Unity 3D UI Essentials Sample Chapter
Unity 3D UI Essentials Sample Chapter
P U B L I S H I N G
pl
C o m m u n i t y
$ 44.99 US
27.99 UK
Sa
m
Simon Jackson
Unity 3D UI Essentials
Unity 3D UI Essentials
ee
D i s t i l l e d
Unity 3D UI Essentials
Leverage the power of the new and improved UI system for Unity
to enhance your games and apps
E x p e r i e n c e
Simon Jackson
I don't stop there, as I regularly contribute to the MonoGame project, adding new features
and new samples before publishing it on NuGet. I also have several of my own open
source projects and actively seek out any new and interesting ones to help with.
By day I am a lowly lead technical architect working in the healthcare software industry
seeking to improve patients' health and care through better software (a challenge to be
sure), but by night I truly soar! Building, tinkering, and educating whilst trying to push
game titles of my own. One day they will pay the bills, but until then I still lead a
double life.
More recently, I achieved the highly acclaimed reward of being a Microsoft MVP in the
ID@Xbox program, for my evangelizing efforts in the game development space. This
won't change much about me, but will give me additional tools to help game developers
out there.
Lastly, you should check out my previous title, which has been one of Packt's best sellers
since its release, especially if you want to learn more about Unity's 2D system. Check it
out here:
.
It truly has been a tormentous year but it looks to be getting better. Through
it all, my wife Caroline has been my tiller, keeping me straight and true
while I tend to my game development and writing efforts. Looking forward,
I'll likely be crafting more of my own experiences with my kids pitching in;
Caitlin, new to game development in school, being my sidekick, Jessica
adding her colorful artistic talent to the mix, and the boys (Alexander and
Nathan) no doubt trying to destroy my efforts through testing.
Additionally, a big thanks to my extended family (Mike and Marilyn) for
helping out with the kids and keeping the writing area a kids-free zone for a
few desperate hours. (It's amazing what a few hours respite can do.)
Also a big shout out to the PWSA (Prader-Willi Syndrome Association
) for their help and support with Alexander, plus the
Warrington Youth Club (
) for their exciting events to keep him
entertained, especially in his more trying times. On that last thread, a very
big thank you to Westland Drive respite (supported by Warrington council),
who give us peace of mind and a night off from time to time; Alexander
certainly loves his visits there.
Finally, thanks to the reviewers of this title (especially Simon W and
Andrew D who joined me from my previous book); they kept me grounded
and on target, although didn't help keeping the page count down. Thanks for
your support guys!
Unity 3D UI Essentials
A new era has dawned, and Unity Technologies have taken a big, bold step. Not only
have they delivered on some big promises for an all new and improved UI system for
Unity projects, but they have also made the source for the new UI completely open
source, giving everyday developers access to the inner workings of the new UI.
These are bold steps indeed. Many felt that the new UI wouldn't live up to the dream that
was sold, as it had been years since they announced it was coming. Delays and rewrites
made it look like it was never going to happen, leaving developers with either having to
live with the existing legacy GUI or pay for some of the more advanced GUI systems on
the asset store (such as NGUI).
Now, after a long and highly deliberated beta program, the new UI system is finally upon
us. In some areas, it meets our expectations; in some, it falls a bit short (however, this is
only the beginning). In other areas however, it has gone far beyond.
Throughout this title, we will peel back the layers of all this new technology to
understand what each component does, how it fits together, and how to use it to build a
fantastic new UI in our projects. Each chapter builds upon the last, to arm you (the
reader) with all the knowledge required to assemble your UI within your projects. You
will not just build on screen menus and options, but to embed UI elements within your
3D game world.
Not only have Unity released the new UI system, they have also given every developer
access to the source that builds the UI, allowing you to better understand how things are
built and enable you to extend the existing controls or even build your own. If you are
feeling adventurous, you can even submit fixes or new features back to Unity for them to
include within Unity itself.
Finally, we can now build what we want, how we want and best of all, it's completely
free and available with the Free license for Unity. All hail and rejoice!
Now what are you waiting for? Pack up your towel, brew a freshly hot cup of tea, crack
open this guide, and start exploring the all new universe of UI.
Chapter 3, Control, Control, You Must Learn Control, Unity UI introduces a heap-load
of new UI controls to suit just about any UI need, from buttons and checkboxes to entire
scrollable areas and layout masks. Here, we will delve deep into how to make the most of
all the controls available.
Chapter 4, Anchors Away, provides a detailed walk-through of how to make the most of
the new Unity UI anchor system and build responsive layouts/designs.
Chapter 5, Screen Space, World Space, and the Camera, Here we finally delve into one
of the most highly anticipated parts of the new UI system: the ability to easily build
perspective UI layouts and add UI elements as 3D objects within a scene.
Chapter 6, Working with the UI Source, looks at all the coding behind the UI framework
and explores the new Event System and UnityEvent frameworks. The chapter finishes
with a walk-through, the open source project for the UI system, allowing you to see just
about every line of code Unity has written for the new UI.
Appendix, The 3D Scene Sample, talks about a flashy 3D demo scene, which was
discussed in Chapter 5, Screen Space, World Space, and the Camera, to show off the UI.
Because this wasn't the focus of the book, it was added as an optional appendix that you
could follow if you wish. The instructions are also available online and as a
downloadable package to enable developers of all levels to make use of it.
Tips, tricks, and an understanding of legacy GUI and what it has done for us
State of play
You may not expect it, but the legacy Unity GUI has evolved over time,
adding new features and improving performance. However, because it has
kept evolving based on the its original implementation, it has been hampered
with many constraints and the ever pressing need to remain backwards compatible
(just look at Windows, which even today has to cater for programs written in BASIC
(http://en.wikipedia.org/wiki/BASIC)). Not to say the old system is bad, it's
just not as evolved as some of the newer features being added to the Unity 4.x and
Unity 5.x series, which are based on newer and more enhanced designs, and more
importantly, a new core.
The main drawback of the legacy GUI system is that it is only drawn in screen space
(drawn on the screen instead of within it) on top of any 3D elements or drawing in
your scenes. This is fine if you want menus or overlays in your title but if you want
to integrate it further within your 3D scene, then it is a lot more difficult.
For more information about world space and screen space, see
this Unity Answers article (http://answers.unity3d.com/
questions/256817/about-world-space-and-localspace.html).
So before we can understand how good the new system is, we first need to get to
grips with where we are coming from. (If you are already familiar with the legacy
GUI system, feel free to skip over this section.)
[8]
Chapter 1
A point of reference
Throughout this book, we will refer to the legacy GUI simply as GUI.
When we talk about the new system, it will be referred to as UI or
Unity UI, just so you don't get mixed-up when reading.
When looking around the Web (or even in the Unity support forums),
you may hear about or see references to uGUI, which was the
development codename for the new Unity UI system.
GUI controls
The legacy GUI controls provide basic and stylized controls for use in your titles.
All legacy GUI controls are drawn during the GUI rendering phase from the built-in
OnGUI method. In the sample that accompanies this title, there are examples of all the
controls in the Assets\BasicGUI.cs script.
For GUI controls to function, a camera in the scene must have the
GUILayer component attached to it. It is there by default on any Camera
in a scene, so for most of the time you won't notice it. However, if you
have removed it, then you will have to add it back for GUI to work.
The component is just the hook for the OnGUI delegate handler, to
ensure it has called each frame.
Like the Update method in scripts, the OnGUI method can be called
several times per frame if rendering is slowing things down. Keep this
in mind when building your own legacy GUI scripts.
Label
Texture
Button
Text fields (single/multiline and password variant)
Box
Toolbars
Sliders
ScrollView
Window
[9]
The Label control supports altering its font settings through the use of the guiText
GameObject property (guiText.font) or GUIStyles. (See the following section on
GUIStyles for more detail.)
To set guiText.font in your script, you would simply apply the
following in your script, either in the Awake/Start functions or
before drawing the next section of text you want drawn in another font:
public Font myFont = new Font("arial");
guiText.font = myFont;
The Label control forms the basis for all controls to display text, and as such,
all other controls inherit from it and have the same behaviors for styling the
displayed text.
[ 10 ]
Chapter 1
The Label control also supports using a Texture for its contents, but not both text
and a texture at the same time. However, you can layer Labels and other controls
on top of each other to achieve the same effect (controls are drawn implicitly in the
order they are called), for example:
public Texture2D myTexture;
void Start() {
myTexture = new Texture2D(125, 15);
}
void OnGUI() {
//Draw a texture
GUI.Label(new Rect(125, 15, 100, 30), myTexture);
//Draw some text on top of the texture using a label
GUI.Label(new Rect(125, 15, 100, 30), "Textoverlay");
}
You can override the order in which controls are drawn by setting
GUI.depth = /*<depth number>*/; in between calls; however,
I would advise against this unless you have a desperate need.
The texture will then be drawn to fit the dimensions of the Label field, By default
it scales on the shortest dimension appropriately. This too can be altered using
GUIStyle to alter the fixed width and height or even its stretch characteristics.
GUIStyles and GUISkins are explained in the later GUI styles
and skins section.
Texture drawing
Not specifically a control in itself, the GUI framework also gives you the ability
to simply draw a Texture to the screen Granted there is little difference to using
DrawTexture function instead of a Label with a texture or any other control. (Just
another facet of the evolution of the legacy GUI). This is, in effect, the same as the
previous Label control but instead of text it only draws a texture, for example:
public Texture2D myTexture;
void Start() {
[ 11 ]
You can also provide scaling and alpha blending values when drawing the texture to
make it better fit in the scene, including the ability to control the aspect ratio that the
texture is drawn in.
A warning though, when you scale the image, it affects the
rendering properties for that image under the legacy GUI system.
Scaling the image can also affect its drawn position. You may have
to offset the position it is drawn at sometimes.
For example:
public Texture2D myTexture;
void Start() {
myTexture = new Texture2D(125, 15);
}
void OnGUI() {
GUI.DrawTexture(new Rect(325, 15, 100, 15), myTexture,
ScaleMode.ScaleToFit,true,0.5f);
}
This will do its best to draw the source texture with in the drawn area with alpha
blending (true) and an aspect ratio of 0.5. Feel free to play with these settings
to get your desired effect.
This is useful in certain scenarios in your game when you want a simple way to
draw a full screen image on the screen on top of all the 3D/2D elements, such as
pause or splash screen. However, like the Label control, it does not receive any
input events (see the Button control for that).
[ 12 ]
Chapter 1
This will pick a region from the source texture (myTexture) 50 pixels wide by
5 pixels high starting from position 10, 10 on the texture. It will then draw this to
the Rect region specified.
However, the DrawTextureWithTexCoords function cannot perform
scaling, it can only perform alpha blending! It will simply draw to fit
the selected texture region to the size specified in the initial Rect.
DrawTextureWithTexCoords has also been used to draw individual
sprites using the legacy GUI, which has a notion of what a sprite is.
The controls also support using a Texture for the button content as well by providing
a texture value for the second parameter as follows:
public Texture2D myTexture;
void Start() {
myTexture = new Texture2D(125, 15);
}
void OnGUI() {
if (GUI.Button(new Rect(25, 40, 120, 30), myTexture))
{ }
}
Like the Label, the font of the text can be altered using GUIStyle or by setting the
guiText property of the GameObject. It also supports using textures in the same
way as the Label. The easiest way to look at this control is that it is a Label that
can be clicked.
Description
TextField
TextArea
PasswordField
[ 14 ]
Chapter 1
Using the TextField control is simple, as it returns the final state of the value that has
been entered and you have to pass that same variable as a parameter for the current
text to be displayed. To use the controls, you apply them in script as follows:
string textString1 = "Some text here";
string textString2 = "Some more text here";
string textString3 = "Even more text here";
void OnGUI() {
textString = GUI.TextField(new Rect(25, 100, 100, 30),
textString1);
textString = GUI.TextArea(new Rect(150, 100, 200, 75),
textString2);
textString = GUI.PasswordField(new Rect(375, 100, 90, 30),
textString3, '*');
}
As with the Label and Button controls, the font of the text displayed can be altered
using either a GUIStyle or guiText GameObject property.
Note that text will overflow within the field if it is too large for
the display area, but it will not be drawn outside the TextField
dimensions. The same goes for multiple lines.
[ 15 ]
Note that using the Box control does not affect any controls you draw
upon it. It is drawn as a completely separate control. This statement
will be made clearer when you look at the Layout controls later in
this chapter.
[ 16 ]
Chapter 1
The example will draw the box background and the Label, Text, and Button controls
on top of the box area and looks like this:
The box control can be useful to highlight groups of controls or providing a simple
background (alternatively, you can use an image instead of just text and color).
As with the other controls, the Box control supports styling using GUIStyle.
As with the Label and Button controls, the font of the text displayed can be altered
using either a GUIStyle or guiText GameObject property.
[ 17 ]
Toolbar panels
The basic GUI controls also come with some very basic automatic layout panels:
the first handles an arrangement of buttons, however these buttons are grouped
and only one can be selected at a time.
As with other controls, the style of the button can be altered using a GUIStyles
definition, including fixing the width of the buttons and spacing.
There are two layout options available, these are:
As with other controls, the Toolbar returns the index of the currently selected button
in the toolbar. The buttons are also the same as the base button control so it also
offers options to support either text or images for the button content.
The RepeatButton control however is not supported.
To implement the toolbar, you specify an array of the content you wish to display in
each button and the integer value that controls the selected button, as follows:
private int toolbarInt;
private string[] toolbarStrings ;
Void Start() {
toolbarInt = 0;
toolbarStrings = { "Toolbar1", "Toolbar2", "Toolbar3" };
}
void OnGUI() {
toolbarInt = GUI.Toolbar(new Rect(25, 200, 200, 30),
toolbarInt, toolbarStrings);
}
[ 18 ]
Chapter 1
The main difference between the preceding controls is that you have to pass the
currently selected index value in to the control and it then returns the new value.
The Toolbar when drawn looks as follows:
As stated, you can also pass an array of textures as well and they will be displayed
instead of the text content.
The main difference between SelectionGrid and Toolbar in code is that with
SelectionGrid you can specify the number of items in a single row and the control will
automatically lay out the buttons accordingly (unless overridden using GUIStyle).
The preceding code will result in the following layout:
On their own, they provide a little more flexibility than just using buttons alone.
[ 19 ]
The slimmer Slider and chunkier Scrollbar controls can both work in either
horizontal or vertical modes and have presets for the minimum and maximum
values allowed.
[ 20 ]
Chapter 1
Like Toolbar and SelectionGrid, you are required to pass in the current value and
it will return the updated value. However, unlike all the other controls, you actually
have two style points, so you can style the bar and the handle separately, giving you
a little more freedom and control over the look and feel of the sliders.
Normally, you would only use the Slider control; The main reason the Scrollbar is
available is that it forms the basis for the next control, the ScrollView control.
Here we have a list that has many items that go beyond the drawable area of the
ScrollView control. We then have the two scrollbars to move the content of the
scroll viewer up/down and left/right to change the view. The background content
is hidden behind a viewable mask that is the width and height of the ScrollView
control's main window.
Styling the control is a little different as there is no base style for it; it relies on
the currently set default GUISkin (see the following GUIStyles section). You can
however set separate GUIStyles for each of the sliders but only over the whole
slider, not its individual parts (bar and handle). If you don't specify styles for each
slider, it will also revert to the base GUIStyle.
[ 21 ]
[ 22 ]
Chapter 1
If you want to, you can also nest ScrollView controls within each other.
The ScrollView control also has some actions to control its use like the ScrollTo
command. This command will move the visible area to the coordinates of the virtual
layer, bringing it into focus. (The coordinates for this are based on the top-left
position of the virtual layer; 0,0 being top-left.)
To use the ScrollTo function on ScrollView, you must use it within the Begin and
End ScrollView commands. For example, we can add a button in ScrollView to
jump to the top-left of the virtual area, for example:
public Vector2 scrollPosition = Vector2.zero;
void OnGUI()
{
scrollPosition = GUI.BeginScrollView(
new Rect(10, 10, 100, 50),
scrollPosition,
new Rect(0, 0, 220, 10));
if (GUI.Button(new Rect(120, 0, 100, 20), "Go to Top Left"))
GUI.ScrollTo(new Rect(0, 0, 100, 20));
GUI.EndScrollView();
}
You can also additionally turn on/off the sliders on either side of the control by
specifying the BeginScrollView statement using the alwayShowHorizontal and
alwayShowVertical properties; these are highlighted here in an updated
GUI.BeginScrollView call:
Vector2 scrollPosition = Vector2.zero;
bool ShowVertical = false; // turn off vertical scrollbar
[ 23 ]
<b></b>
This gives text a Bold format, for example:
The <b>quick</b> brown <b>Fox</b> jumped over the <b>lazy Frog</b>
<i></i>
Using this tag will give text an Italic format, for example:
The <b><i>quick</i></b> brown <b>Fox</b><i>jumped</i> over the
<b>lazy Frog</b>
<size></size>
As you can probably guess, this tag will alter the Size of the text it surrounds.
For reference, the default size for the font is set by the font itself.
[ 24 ]
Chapter 1
For example:
The <b><i>quick</i></b> <size=50>brown <b>Fox</b></size> <i>jumped</
i> over the <b>lazy Frog</b>
brown Fox
<color></color>
Lastly, you can specify different colors for text surrounded by the Color tag.
The color itself is denoted using its 8-digit RGBA hex value, for example:
The <b><i>quick</i></b> <size=50><color=#a52a2aff>brown</color>
<b>Fox</b></size> <i>jumped</i> over the <b>lazy Frog</b>
Note that the color is defined using normal RGBA color space
notation (http://en.wikipedia.org/wiki/RGBA_color_
space) in hexadecimal form with two characters per color, for
example, RRGGBBAA. Although the color property does also
support the shorter RGB color space, which is the same notation
but without the A (Alpha) component, for example,. RRGGBB
brown Fox
(If you are reading this in print, the previous word brown is in the color brown.)
You can also use a color name to reference it but the pallet is quite
limited; for more details, see the Rich Text manual reference page at
http://docs.unity3d.com/Manual/StyledText.html.
<material></material>
<quad></quad>
These only apply when associated to an existing mesh. The material is one of the
materials assigned to the mesh, which is accessed using the mesh index number
(the array of materials applied to the mesh). When applied to a quad, you can also
specify a size, position (x, y), width, and height to the text.
[ 25 ]
The text mesh isn't well documented and is only here for reference;
as we delve deeper into the new UI system, we will find much better
ways of achieving this.
Grouping controls
The legacy GUI allow you to group controls together on the screen, making all
positions for the group relative to the group's position. This means that if you started
a group at position X 50 and Y 50, then all child control positions within the group
would start at 50,50 when they define their position as 0,0.
Like the ScrollView control, each group has a beginning and an end to define the
scope of all the controls within the group, for example:
void OnGUI() {
//Start a group at position 50, 50. 150 width and 60 height
GUI.BeginGroup(new Rect (50,50,150,60));
//Draw a label with a 10, 10 offset in the group
GUI.Label(new Rect (10, 10, 100, 30), "Label in a Group");
GUI.EndGroup();
}
Here the label is drawn within the group bounds, and as the group starts at X 50,
the Labels screen position will be at X 60 (50 + 10). Anything positioned or
overflowing the group's bounds will not be drawn.
The group, like other controls, can also specify content within the group as text or a
texture with appropriate GUIStyles.
What is odd is that unlike the rest of the controls, if you specify text
content in the function, the default color of text is white, whereas if you
specify text in the content parameter for the BeginGroup function, the
text in the group is black by default. It's also left justified instead
of centered.
Additionally, by default the group does not support Rich Text
Formatting unlike the other controls, so you will need to apply
GUIStyle to change that.
[ 26 ]
Chapter 1
Naming controls
With each control that you implement through script, you can name them as you
place them; this is essential if you want to control flow and access to each field from
the keyboard or to derive logic based on the currently selected/focused control.
Now unlike most other Unity functionality, you cannot directly name controls,
there is no Name field on the properties of the controls as they are just commands
to the GUI system to draw things to the screen, kind of like a rendering pipeline.
So to name GUI controls in Unity, we simply need to tell the GUI system that the
next control we are going to draw has a name, as follows:
string login = "Would you like to play a game?";
void OnGUI() {
GUI.SetNextControlName("MyAwesomeField");
login = GUI.TextField(new Rect(10, 10, 200, 20), login);
}
Getting in focus
With names defined on controls, you could then define which control you were
focusing on. To focus on a specific control, you would simply need to call:
GUI.FocusControl("MyAwesomeField");
This would then change the user's input focus or selection to the specific GUI control
with that name.
Once you have a control in focus, you then discover the name of the specific control
in focus by calling:
string selectedControl = GUI.GetNameOfFocusedControl();
If the control in focus has a name, it will return the name you set for that control.
If no control is in focus or the control in focus has no name, it will return an
empty string.
To start, create a new script called IntermediateGUI in your project (the full sample
can be found in the project available with this book in the code download) and
replace its contents with the following:
using UnityEngine;
[ExecuteInEditMode]
public class IntermediateGUI : MonoBehaviour {
public string username = "Enter username";
public string password = "Enter password";
private bool passwordInError = false;
private string passwordErrorMessage =
"<color=red>Password too short</color>";
}
This gives a basic class with some of the parameters you might expect in a logon
or registration form.
To this we'll add a simple function to validate the password entered to ensure it
meets our stringent security policy:
void CheckUserPasswordAndRegister()
{
if (password.Length < 6)
{
//If the password is not long enough, mark it in error
//and focus on the password field
passwordInError = true;
GUI.FocusControl("PasswordField");
} else
{
passwordInError = false;
GUI.FocusControl("");
//Register User
}
}
[ 28 ]
Chapter 1
GUI.SetNextControlName("UsernameField");
username = GUI.TextField(new Rect(10, 40, 130, 20), username);
GUI.SetNextControlName("PasswordField");
password = GUI.PasswordField(new Rect(10, 70, 130, 20),
password,'*');
if (passwordInError)
{
GUI.Label (new Rect (10, 100, 200, 20),
passwordErrorMessage);
}
if (Event.current.isKey &&
Event.current.keyCode == KeyCode.Return &&
GUI.GetNameOfFocusedControl() == "PasswordField")
{
CheckUserPasswordAndRegister();
}
if (GUI.Button(new Rect(80, 130, 65, 20), "Register"))
{
CheckUserPasswordAndRegister();
}
GUI.EndGroup();
}
Note that the Event keyword here relates to the legacy GUI event
system for handling user input. See the Event section later in this
chapter for more information.
This is NOT to be confused with the UnityEvent system introduced
with the new UI system.
[ 29 ]
In this example, we draw a box, a text field, and a password field together with a
simple button within a group, which is then centered on the screen.
We check whether the user hits the Enter key and whether they are on the password
field (checked using the GUI.GetNameOfFocusedControl() function) and we try to
register them. The same happens if the user clicks on the Register button.
If the user's password is longer than six characters, then they are registered; if not,
then the passwordInError flag is set to True, which causes the additional label to
be drawn, this then warns the user that their password could be broken easily by
a 6-year-old.
Don't forget to add the IntermediateGUI script to an active
GameObject in a scene or Main Camera to see the result!
Tooltips
Each of the GUI controls can also have a tooltip associated with it to display some
additional text when it is either in focus or the mouse is hovering over the control.
Adding a tooltip is simple; you just need to replace the content of the control when it
is being drawn using the GUIContent class. For example, we can update the Register
button in the previous script as follows:
if (GUI.Button(new Rect(80, 130, 65, 20),
new GUIContent("Register", "My Tooltip")))
{
CheckUserPasswordAndRegister();
}
With the tooltip defined, we just then need to display the current tooltip somewhere
on the screen, usually as a label, but it can be any control that can display text (input
fields are not recommended however), so add the following after the button block
but before EndGroup():
GUI.Label (new Rect (10, 120, 65, 20), GUI.tooltip);
This simply gets the content of the current tooltip in focus and returns the tooltip text
for that control.
GUIContent also has several other options for displaying text and
texture variants, so it's worth checking out some more.
[ 30 ]
Chapter 1
The drag state of Window; as in, the window can be dragged by holding
on with a mouse or touch
The draw order of each Window; this allows sorting of draw windows on
top of each other
To create a Window control, you first need to define a new method callback for the
Window using the following signature:
void DoMyWindow(int windowID)
{
}
[ 31 ]
This method is where you will add all your GUI code using the previous examples;
each control is positioned is based off the top-left position of the window when it is
displayed (same as the Group and ScrollView controls described earlier).
Additionally, you can specify any of the previous options for the window,
for example:
void DoMyWindow(int windowID)
{
GUI.Label(new Rect(25, 15, 100, 30), "Label");
// Make the window Draggable
GUI.DragWindow();
}
With your Window method in place, you just need to call the GUI.Window function
to open it along with the property to track the Window's location:
private Rect rctWindow1;
void OnGUI()
{
Rect rctWindow1;
rctWindow1 = GUI.Window(0,
rctWindow1,
DoMyWindow,
"Controls Window");
}
If you want a modal window, then you would need to instantiate the window with
the GUI.ModalWindow function instead of the Window function:
rctWindow1 = GUI.ModalWindow(0, rctWindow1, DoMyWindow, "Modal
Controls Window");
If we take all the controls together (that we have created so far in this chapter),
it would create a Window view, as shown in the following screenshot:
For a complete end-to-end example, please see the code download
package, which has all this defined.
[ 32 ]
Chapter 1
[ 33 ]
A Name
A texture or text color for the different states of the control it's attached to
(Normal, Hover, Active, and Focused)
The border, margin, padding, and overflow sizes for the control
(for each edge)
A Font (with suitable size, style, alignment, word wrapping, and rich
text support options)
It is worth noting that having too many different GUIStyles all over
the place can become very inefficient and hard to maintain. If you
find you are using a lot of GUIStyles then I'd recommend you create
a single script attached to a common object (say Main Camera) in
your scene with all your GUIStyle's defined and have each script take
GUIStyle references from there.
[ 34 ]
Chapter 1
When you attach the preceding script with the GUIStyle property to a GameObject
in your scene, it will look like this in Inspector:
Note that the first time you open it in the editor you will
get NullReferenceException in the console window;
this is just because you haven't configured GUIStyle yet.
If you don't want to apply a style to each and every control directly, you can then
optionally create GUISkin, which contains all the styles for each control type.
This is then applied using the GUI class prior to drawing any controls.
A GUISkin also has some additional options that apply to the GUI, which include:
Custom styles (an array of GUIStyle properties you can then reuse
on controls)
[ 35 ]
To demonstrate, click on the Create button in the project folder view and select
GUISkin, which will give you a new GUISkin asset in the project view. By selecting
it, you will see the following window in Inspector:
As you can see, it contains all the options for altering the style globally for each
control. To use GUISkin, create a new script called GUISkins, then replace its
contents with the following:
using UnityEngine;
[ExecuteInEditMode]
public class GUISkins : MonoBehaviour {
public GUISkin MySkin;
void OnGUI()
{
GUI.skin = mySkin;
GUI.Label(new Rect(25, 15, 100, 30), "Label");
//Draw the rest of your controls
}
}
Then attach the GUISkins script to Main Camera in your current scene
(disabling any other scripts currently attached) and drag the GUISkin you
have created and apply it to the My Skin property of the script in the inspector:
[ 36 ]
Chapter 1
By setting the skin at the beginning of any GUI drawing, any and all controls drawn
will now use your custom skin instead of the Unity default. If you wish, you can use
several skins by just changing the skin before drawing more controls.
For some of the best examples of GUISkins, try installing the Unity Extra GUI Skins
asset (http://bit.ly/UnityExtraGUISkins), which is a collection of skin samples
built by Unity themselves (and it's free).
Note that if you want to reuse your own skins in other projects
(or sell more skins through the asset store), then you can export
them using Unity's Export Package option under Assets in the
menu. For more details, check out http://docs.unity3d.com/
Manual/HOWTO-exportpackage.html
[ 37 ]
To access the events you simply need to query the Event.current property to get
the current Event state. (The Event state updates when there is a change, until then
you will get the last/previous state.)
The logon example earlier shows an example for using events, where we detect if
the user has pressed a key and if that key is the Enter key as shown in this script:
if (Event.current.isKey &&
Event.current.keyCode == KeyCode.Return &&
GUI.GetNameOfFocusedControl() == "PasswordField")
{
CheckUserPasswordAndRegister();
}
Along with the events, the GUI class also provides some additional properties you
can query or set in the OnGUI method, namely:
enabled: Is the GUI enabled and displayed on the screen. Can it be used to
changed: This returns true if any controls' values have changed since the last
call of OnGUI.
color: This is the global color tint for the GUI layout.
contentColor: This is the global text color tint for the GUI.
[ 38 ]
Chapter 1
depth: This is the depth order for the current GUI script. This is useful if you
have GUI elements in more than one script and want to layer them.
All of these elements can be used to override all controls or individual controls by
setting them in between controls.
Layout controls
If you prefer not to hand draw the position of every single control in your GUI,
Unity does offer some automatic layout controls from the GUILayout class.
The Layout controls (using GUILayout instead of just GUI) have the same set of
controls as the normal GUI class (hence I'm not going to describe them all over
again), the main difference is that you do not need to specify a Rect area to draw
the control, as it will just be drawn at the first suitable location; any further controls
added will be laid out appropriately with enough spacing between the controls.
You can also control the spacing and even if you want, any empty space between the
controls using the Width, Height, and Spacing properties (Space/FlexibleSpace) of
GUILayout, following the same rules as for GUI controls (setting up the GUILayout
before drawing a control).
If you don't want the layout to take up the maximum space for a control,
you also have the settings for Width (MaxWidth/MinWidth) and Height
(MaxHeight/MinHeight).
The main differences are as follows:
BeginArea
Instead of defining Groups, you define Areas. Apart from the name, they behave
exactly the same. This is the only layout control that takes a Rect parameter to
specify where you want to draw the controls (excluding Windows of course); all
GUILayout controls are then aligned to Area in the same way they are in Group.
It's recommended that when using GUILayout controls that you
place them in an Area for the best effect.
[ 39 ]
Enter Thunderdome
Now that you've seen what Unity has had available for so long with the legacy GUI
(and if you have experienced it you will undoubtedly shudder at this point), it is a
very welcome relief that the UI system has received such an overhaul in Unity 4.6.
It has been a long time coming and very much anticipated!
Note that this section is just a preliminary overview so you know
what's coming. Each section will be described in depth in the
following chapters.
Recognizing the need for change, Unity set upon the path of redesigning the GUI
system from the ground up. They have looked at what games have needed, what the
community has built (even with the limitations and restrictions of not having access
to Unity's core) and then sprinkled some fairy dust and hey presto, the new Unity UI
system was born.
[ 40 ]
Chapter 1
It has been a long, hard road with many bumps in the way, but the journey has
begun (I say begun because the Unity UI journey does not end with Unity 4.6;
it will continue to evolve into Unity 5 and beyond like many other components).
With a keen eye on the future, the new Unity UI system delivers on several core
points, namely:
Extensibility: Each and every control is a script and you can create new
scripts to derive from them and create your own controls.
Uses sprites: The new Unity UI system is predominately built on top of the
new sprite system introduced in Unity 4.3. It has also however extended the
sprite system with some new features as well.
Exposed events: Each control has its own events which you can attach to and
extend upon.
Tight integration with rendering and update loops: Because they are
GameObjects, you can even override the default rendering and updating
of a control.
Animation: Each control can be fully animated using the new Animator
dope sheet and Mecanim. Some controls (such as the button) leverage
Mecanim to do state-driven control. There are even animation specific events.
FREE: Unity UI comes as standard as part of the free license version of Unity
(indie developers rejoice).
Open source: Unity has made the source for the UI system open source and
available for anyone to look at and even offer fixes / new suggestions,
to coders delight.
New layouts
The layout features begin the story of the new Unity UI; they set the stage and
ultimately define where controls will be drawn, in which direction they will be
drawn, and also how they fit within a certain area.
[ 41 ]
Rect Transform
Introduced in 4.3 with the new Sprite functionality, the Rect Transform component
provides a defining region for any 2D element within the Unity system. However,
like most things in 4.6, it has received significant updates allowing more control over
the area it manages as shown here:
It also sports a new button in the editor (called the Rect Tool) to edit and manage
Rect Transform from the scene view, as shown in the following screenshot:
The Canvas
At the core of all Unity UI drawings, is the new Canvas control. It acts as the paint
board for your Unity UI controls (and even other canvases), once rendered the
canvas is drawn to the relative point in your scene.
Thanks to vast improvements this canvas can be drawn in basic 2D overlay mode
(same as the legacy GUI system), in 2D camera space (adding perspective), or
even directly in 3D world space like as any other traditional 3D object (such as a
rendertarget for UI) as shown here:
[ 42 ]
Chapter 1
Groups
In the legacy GUI, groups were defined by the controls themselves;
if you wanted to orientate multiple controls together in a particular fashion,
you simply couldn't.
With the new Unity UI system, you can define several layout groups.
[ 43 ]
Toggle Group
A Toggle Group manages arranges toggle controls in to a group where only one
can be active at a time (Like a Multiple choice selection where only one option can
be chosen).
Canvas Group
A Canvas Group allows you to generically group child UI controls together and
affect several common properties from the group, for example, the Alpha value
of all child items:
Masking
Recognizing the need for generic masking capabilities within the new Unity UI system
(the ability to hide portions of UI within a certain region), they created a new Mask
component. This can be added to any GameObject and any child objects outside the
bounds of the parent GameObject would not be drawn, either partially or fully.
The Image control (highlighted later in the chapter) also includes an additional
masking feature, when the Image Type property of an image is set to Filled;
it gives several additional masking options to gradually bring the image into
view. Just for reference now, we'll go into this in a lot more detail later.
New controls
Something old, something new, something borrowed, something blue.
Obviously when we look at a GUI, there is only so much that is really needed and
Unity has recognized this. Starting with a fresh slate, they have looked at what it
means to create a stunning UI and what you need to build one.
[ 44 ]
Chapter 1
So with this fresh start, here are the new Unity UI controls:
Control
Description
Selectable
The selectable component is the base object for anything that needs
interaction, and it basically turns any other component into a
button. Note that it cannot be used on the same GameObject with
something that is already selectable (button, toggle, and sliderbar).
(only available in
the component list)
Panel
Text
If text is your aim, then this control is for you. It gives you text
options like font, color, font style, and overflow. Can also be set to
resize text to fit the container it is in.
Image
Raw Image
Button
If you need a big red (color optional) button to press, then this
control is for you. The button has received the biggest overhaul
by far with so many options it will likely take a chapter on its
own to explain.
It also includes a new UnityEvent framework that allows you to
create behaviors that can affect other objects or scripts directly from
the editor.
You can even set different colors for different states of the button,
swap out images, or if you wish, use Mecanim and the new
animation system to animate the button between states.
Toggle
Switch it on, switch it off. The toggle takes the button behavior and
extends it as a prime example of what extensibility features are in
the new UI framework. It adds additional properties to the button
framework to identify the checkbox graphic and a grouping option
should you want to group checkboxes (using a Toggle group).
Scrollbar
It slices, it dices, it even slides as well. Your typical scroll bar with
a handle, fully customizable with options to control the direction,
minimum and maximum values, step size, and number of steps to
slide between. Also includes the event system used for buttons for
when the value changes.
Slider
Control extensibility
One very cool feature of the new UI system is that practically every component is
a script, meaning it can be used as the base for any new scripts you create. You can
either use them as is or even extend them further.
In Chapter 6, Working with the UI Source, we will cover the coding behind all these
components including a walk through the open source library. I'll even throw in a
load of examples and reusable components from the community and myself.
Animation
A core tenant of the new UI system (since it is built upon the core of the new 2D
sprite system) was animation. Every single control or component of the new Unity
UI system is able to be fully animated.
Not only that, but it also gives different modes for how properties can be animated,
from static fixed values to dynamic values that will alter and update with the
controls behavior.
[ 46 ]
Chapter 1
I'll point these out again in some of the chapters where you will get the most use out
of them or where they are relevant.
The most notable assets at the time of writing are the following.
TextMeshPro ($65)
This is a fantastic text management system that helps to bridge the gaps and the
limitations in Unity's aging text rendering system. Unity themselves have noted on
several occasions they want to rip out the text system and replace it with something
better, until that happens, the best asset to help with text generation from within
Unity (not just getting an artist to build lots of text assets) is TextMeshPro.
TextMeshPro has been around for quite a while now and has run with the
leaders to get it updated for the new UI system but the author didn't stop there.
TextMeshPro has gone far and beyond its humble text rendering beginnings to
add such features as improved alignment/indentation and rich text support, even
adding vertex animation for the generated text! (Just check out http://bit.ly/
TextMeshProAnimation.)
You can find TextMeshPro on the asset store here: http://bit.ly/
UnityUITextMeshPro.
[ 47 ]
MenuPage ($10)
Not every asset for the new UI has to be a big beast of a tool meant to save you
hours, sometimes you just need something to get you off the ground and using the
new UI with great effect. This is where MenuPage comes in.
Put simply it's a new asset on the store aimed at building menu systems using the
new UI system automatically. They are fully configured, laid out effectively and
offer some advanced features such as fading, transitions, and much more.
What's even better is that all the source code is there and is fully documented/
commented, so you can learn from some of the best coders out there purveying
their wares.
You can find MenuPage on the asset store here: http://bit.ly/UnityUIMenuPage.
Summary
So now we have a deep appreciation of the past and a glimpse into the future.
One thing you might realize is that there is no one stop shop when it comes to
Unity; each feature has its pros and cons and each has its uses. There may still
be cases when it is just easier to use the Unity legacy GUI to achieve an effect
(still using the basic GUI.DrawTexture for a splash screen for example, although
even that is very easy with the new UI system) provided you take the performance
concerns on board with mobile devices. It all comes down to what you want to
achieve and the way you want to achieve it; never dismiss anything just because
it's old (except for GUIText and GUITexture, they are just really really old)
[ 48 ]
Chapter 1
Whistlestop tour of the new Unity UI system and what we can expect from
this title
In the next chapter, we will start with the underlying framework and guts behind
the new GUI system, namely:
The new Rect Transform control (not just for Unity UI)
What Unity have done for scaling and resolution for UIs
The all new and improved Event messaging system for the Unity UI system,
complete with new shiny raycasting features and helpers
It promises to be a fun ride, and once we are through that, then in chapter 3,
Control, Control, You Must Learn Control we can move on to actually building
some UI and then placing it in your game scenes in weird and wonderful ways.
Now stop reading this and turn the page already!!
[ 49 ]
www.PacktPub.com
Stay Connected: