22 min read

In this article by Charles Pearson, the author of Learning NGUI for Unity, we will talk about C# scripting with NGUI. We will learn how to handle events and interact with them through code. We’ll use them to:

  • Play tweens with effects through code
  • Implement a localized tooltip system
  • Localize labels through code
  • Assign callback methods to events using both code and the Inspector view

We’ll learn many more useful C# tips throughout the book. Right now, let’s start with events and their associated methods.

(For more resources related to this topic, see here.)

Events

When scripting in C# with the NGUI plugin, some methods will often be used. For example, you will regularly need to know if an object is currently hovered upon, pressed, or clicked. Of course, you could code your own system—but NGUI handles that very well, and it’s important to use it at its full potential in order to gain development time.

Available methods

When you create and attach a script to an object that has a collider on it (for example, a button or a 3D object), you can add the following useful methods within the script to catch events:

  • OnHover(bool state): This method is called when the object is hovered or unhovered. The state bool gives the hover state; if state is true, the cursor just entered the object’s collider. If state is false, the cursor has just left the collider’s bounds.
  • OnPress(bool state): This method works in the exact same way as the previous OnHover() method, except it is called when the object is pressed. It also works for touch-enabled devices. If you need to know which mouse button was used to press the object, use the UICamera.currentTouchID variable; if this int is equal to -1, it’s a left-click. If it’s equal to -2, it’s a right-click. Finally, if it’s equal to -3, it’s a middle-click.
  • OnClick(): This method is similar to OnPress(), except that this method is exclusively called when the click is validated, meaning when an OnPress(true) event occurs followed by an OnPress(false) event. It works with mouse click and touch (tap).

    In order to handle double clicks, you can also use the OnDoubleClick() method, which works in the same way.

  • OnDrag(Vector2 delta): This method is called at each frame when the mouse or touch moves between the OnPress(true) and OnPress(false) events. The Vector2 delta argument gives you the object’s movement since the last frame.
  • OnDrop(GameObject droppedObj): This method is called when an object is dropped on the GameObject on which this script is attached. The dropped GameObject is passed as the droppedObj parameter.
  • OnSelect(): This method is called when the user clicks on the object. It will not be called again until another object is clicked on or the object is deselected (click on empty space).
  • OnTooltip(bool state): This method is called when the cursor is over the object for more than the duration defined by the Tooltip Delay inspector parameter of UICamera. If the Sticky Tooltip option of UICamera is checked, the tooltip remains visible until the cursor moves outside the collider; otherwise, it disappears as soon as the cursor moves.
  • OnScroll(float delta): This method is called when the mouse’s scroll wheel is moved while the object is hovered—the delta parameter gives you the amount and direction of the scroll.

    If you attach your script on a 3D object to catch these events, make sure it is on a layer included in Event Mask of UICamera.

Now that we’ve seen the available event methods, let’s see how they are used in a simple example.

Example

To illustrate when these events occur and how to catch them, you can create a new EventTester.cs script with the following code:

void OnHover(bool state)
{
Debug.Log(this.name + " Hover: " + state);
}
 
void OnPress(bool state)
{
Debug.Log(this.name + " Pressed: " + state);
}
 
void OnClick()
{
Debug.Log(this.name + " Clicked");
}
 
void OnDrag(Vector2 delta)
{
Debug.Log(this.name + " Drag: " + delta);
}
 
void OnDrop(GameObject droppedObject)
{
Debug.Log(droppedObject.name + " dropped on " + this.name);
}
 
void OnSelect(bool state)
{
Debug.Log(this.name + " Selected: " + state);
}
 
void OnTooltip(bool state)
{
Debug.Log("Show " + this.name + "'s Tooltip: " + state);
}
 
void OnScroll(float delta)
{
Debug.Log("Scroll of " + delta + " on " + this.name);
}

The above highlighted lines are the event methods we discussed, implemented with their respective necessary arguments.

Attach our Event Tester component now to any GameObject with a collider, like our Main | Buttons | Play button. Hit Unity’s play button. From now on, events that occur on the object they’re attached to are now tracked in the Console output:

 Learning NGUI for Unity

I recommend that you keep the EventTester.cs script in a handy file directory as a reminder for available event methods in the future. Indeed, for each event, you can simply replace the Debug.Log() lines with the instructions you need.

Now we know how to catch events through code. Let’s use them to display a tooltip!

Creating tooltips

Let’s use the OnTooltip() event to show a tooltip for our buttons and different options, as shown in the following screenshot:

 Learning NGUI for Unity

The tooltip object shown in the preceding screenshot, which we are going to create, is composed of four elements:

  • Tooltip: The tooltip container, with the Tooltip component attached.
  • Background: The background sprite that wraps around Label.
  • Border: A yellow border that wraps around Background.
  • Label: The label that displays the tooltip’s text.

We will also make sure the tooltip is localized using NGUI methods.

The tooltip object

In order to create the tooltip object, we’ll first create its visual elements (widgets), and then we’ll attach the Tooltip component to it in order to define it as NGUI’s tooltip.

Widgets

First, we need to create the tooltip object’s visual elements:

  1. Select our UI Root GameObject in the Hierarchy view.
  2. Hit Alt + Shift + N to create a new empty child GameObject.
  3. Rename this new child from GameObject to Tooltip.
  4. Add the NGUI Panel (UIPanel) component to it.
  5. Set this new Depth of UIPanel to 10.

In the preceding steps, we’ve created the tooltip container. It has UIPanel with a Depth value of 10 in order to make sure our tooltip will remain on top of other panels.

Now, let’s create the faintly transparent background sprite:

  1. With Tooltip selected, hit Alt + Shift + S to create a new child sprite.

  2. Rename this new child from Sprite to Background.

Select our new Tooltip | Background GameObject, and configure UISprite, as follows:

Learning NGUI for Unity

Perform the following steps:

  1. Make sure Atlas is set to Wooden Atlas.

  2. Set Sprite to the Window sprite.
  3. Make sure Type is set to Sliced.
  4. Change Color Tint to {R: 90, G: 70, B: 0, A: 180}.
  5. Set Pivot to top-left (left arrow + up arrow).
  6. Change Size to 500 x 85.
  7. Reset its Transform position to {0, 0, 0}.

Ok, we can now easily add a fully opaque border with the following trick:

  1. With Tooltip | Background selected, hit Ctrl + D to duplicate it.

  2. Rename this new duplicate to Border.

Select Tooltip | Border and configure its attached UI Sprite, as follows:

 Learning NGUI for Unity

Perform the following steps:

  1. Disable the Fill Center option.

  2. Change Color Tint to {R: 255, G: 220, B: 0, A: 255}.
  3. Change the Depth value to 1.
  4. Set Anchors Type to Unified.
  5. Make sure the Execute parameter is set to OnUpdate.
  6. Drag Tooltip | Background in to the new Target field.

By not filling the center of the Border sprite, we now have a yellow border around our background. We used anchors to make sure this border always wraps the background even during runtime—thanks to the Execute parameter set to OnUpdate.

Right now, our Game and Hierarchy views should look like this:

 Learning NGUI for Unity

Let’s create the tooltip’s label. With Tooltip selected, hit Alt + Shift + L to create a new label. For the new Label GameObject, set the following parameters for UILabel:

 Learning NGUI for Unity

  1. Set Font Type to NGUI, and Font to Arimo20 with a size of 40.

  2. Change Text to [FFCC00]This[FFFFFF] is a tooltip.
  3. Change Overflow to ResizeHeight.
  4. Set Effect to Outline, with an X and Y of 1 and black color.
  5. Set Pivot to top-left (left arrow + up arrow).
  6. Change X Size to 434. The height adjusts to the text amount.
  7. Set the Transform position to {33, -22, 0}.

Ok, good. We now have a label that can display our tooltip’s text. This label’s height will adjust automatically as the text gets longer or shorter.

Let’s configure anchors to make sure the background always wraps around the label:

  1. Select our Tooltip | Background GameObject.

  2. Set Anchors Type to Unified.
  3. Drag Tooltip | Label in the new Target field.
  4. Set the Execute parameter to OnUpdate.

Great! Now, if you edit our tooltip’s text label to a very large text, you’ll see that it adjusts automatically, as shown in the following screenshot:

 Learning NGUI for Unity

UITooltip

We can now add the UITooltip component to our tooltip object:

  1. Select our UI Root | Tooltip GameObject.

  2. Click the Add Component button in the Inspector view.
  3. Type tooltip with your keyboard to search for components.
  4. Select Tooltip and hit Enter or click on it with your mouse.

Configure the newly attached UITooltip component, as follows:

  1. Drag UI Root | Tooltip | Label in the Text field.

  2. Drag UI Root | Tooltip | Background in the Background field.

The tooltip object is ready! It is now defined as a tooltip for NGUI. Now, let’s see how we can display it when needed using a few simple lines of code.

Displaying the tooltip

We must now show the tooltip when needed. In order to do that, we can use the OnTooltip() event, in which we request to display the tooltip with localized text:

  1. Select our three Main | Buttons | Exit, Options, and Play buttons.

  2. Click the Add Component button in the Inspector view.
  3. Type ShowTooltip with your keyboard.
  4. Hit Enter twice to create and attach the new ShowTooltip.cs script to it.
  5. Open this new ShowTooltip.cs script.

First, we need to add this public key variable to define which text we want to display:

// The localization key of the text to display
public string key = "";

Ok, now add the following OnTooltip() method that retrieves the localized text and requests to show or hide the tooltip depending on the state

bool:
// When the OnTooltip event is triggered on this object
void OnTooltip(bool state)
{
// Get the final localized text
string finalText = Localization.Get(key);
 
// If the tooltip must be removed...
if(!state)
{
// ...Set the finalText to nothing
finalText = "";
}
 
// Request the tooltip display
UITooltip.ShowText(finalText);
}

Save the script. As you can see in the preceding code, the Localization.Get(string key) method returns localized text of the corresponding key parameter that is passed. You can now use it to localize a label through code anytime! In order to hide the tooltip, we simply request UITooltip to show an empty tooltip.

To use Localization.Get(string key), your label must not have a UILocalize component attached to it; otherwise, the value of UILocalize will overwrite anything you assign to UILabel.

Ok, we have added the code to show our tooltip with localized text. Now, open the Localization.txt file, and add these localized strings:

// Tooltips
Play_Tooltip, "Launch the game!", "Lancer le jeu !"
Options_Tooltip, "Change language, nickname, subtitles...", "Changer la langue, le pseudo, les sous-titres..."
Exit_Tooltip, "Leaving us already?", "Vous nous quittez déjà ?"

Now that our localized strings are added, we could manually configure the key parameter for our three buttons’ Show Tooltip components to respectively display Play_Tooltip, Options_Tooltip, and Exit_Tooltip.

But that would be a repetitive action, and if we want to add localized tooltips easily for future and existing objects, we should implement the following system: if the key parameter is empty, we’ll try to get a localized text based on the GameObject’s name.

Let’s do this now! Open our ShowTooltip.cs script, and add this Start() method:

// At start
void Start()
{
// If key parameter isn't defined in inspector...
if(string.IsNullOrEmpty(key))
{
// ...Set it now based on the GameObject's name
key = name + "_Tooltip";
}
}

Click on Unity’s play button. That’s it! When you leave your cursor on any of our three buttons, a localized tooltip appears:

 Learning NGUI for Unity

The preceding tooltip wraps around the displayed text perfectly, and we didn’t have to manually configure their Show Tooltip components’ key parameters!

Actually, I have a feeling that the display delay is too long. Let’s correct this:

  1. Select our UI Root | Camera GameObject.

  2. Set Tooltip Delay of UICamera to 0.3.

That’s better—our localized tooltip appears after 0.3 seconds of hovering.

Adding the remaining tooltips

We can now easily add tooltips for our Options page’s element. The tooltip works on any GameObject with a collider attached to it. Let’s use a search by type to find them:

  1. In the Hierarchy view’s search bar, type t:boxcollider

  2. Select Checkbox, Confirm, Input, List (both), Music, and SFX:Learning NGUI for Unity
  3. Click on the Add Component button in the Inspector view.
  4. Type show with your keyboard to search the components.
  5. Hit Enter or click on the Show Tooltip component to attach it to them.

For the objects with generic names, such as Input and List, we need to set their key parameter manually, as follows:

  1. Select the Checkbox GameObject, and set Key to Sound_Tooltip.

  2. Select the Input GameObject, and set Key to Nickname_Tooltip.
  3. For the List for language selection, set Key to Language_Tooltip.
  4. For the List for subtitles selection, set Key to Subtitles_Tooltip.

To know if the selected list is the language or subtitles list, look at Options of its UIPopup List: if it has the None option, then it’s the subtitles selection.

Finally, we need to add these localization strings in the Localization.txt file:

Sound_Tooltip, "Enable or disable game sound", "Activer ou désactiver le son du jeu"
Nickname_Tooltip, "Name used during the game", "Pseudo utilisé lors du jeu"
Language_Tooltip, "Game and user interface language", "Langue du jeu et de l'interface"
Subtitles_Tooltip, "Subtitles language", "Langue des sous-titres"
Confirm_Tooltip, "Confirm and return to main menu", "Confirmer et retourner au menu principal"
Music_Tooltip, "Game music volume", "Volume de la musique"
SFX_Tooltip, "Sound effects volume", "Volume des effets"

Hit Unity’s play button. We now have localized tooltips for all our options! We now know how to easily use NGUI’s tooltip system. It’s time to talk about Tween methods.

Tweens

The tweens we have used until now were components we added to GameObjects in the scene. It is also possible to easily add tweens to GameObjects through code.

You can see all available tweens by simply typing Tween inside any method in your favorite IDE. You will see a list of Tween classes thanks to auto-completion, as shown in the following screenshot:

 Learning NGUI for Unity

The strong point of these classes is that they work in one line and don’t have to be executed at each frame; you just have to call their Begin() method!

Here, we will apply tweens on widgets, but keep in mind that it works in the exact same way with other GameObjects since NGUI widgets are GameObjects.

Tween Scale

Previously, we’ve used the Tween Scale component to make our main window disappear when the Exit button is pressed. Let’s do the same when the Play button is pressed, but this time we’ll do it through code to understand how it’s done.

DisappearOnClick Script

We will first create a new DisappearOnClick.cs script that will tween a target’s scale to {0.01, 0.01, 0.01} when the GameObject it’s attached to is clicked on:

  1. Select our UI Root | Main | Buttons | Play GameObject.

  2. Click the Add Component button in the Inspector view.
  3. Type DisappearOnClick with your keyboard.
  4. Hit Enter twice to create and add the new DisappearOnClick.cs script.
  5. Open this new DisappearOnClick.cs script.

First, we must add this public target GameObject to define which object will be affected by the tween, and a duration float to define the speed:

// Declare the target we'll tween down to {0.01, 0.01, 0.01}
public GameObject target;
// Declare a float to configure the tween's duration
public float duration = 0.3f;

Ok, now, let’s add the following OnClick() method, which creates a new tween towards {0.01, 0.01, 0.01} on our desired target using the duration variable:

// When this object is clicked
private void OnClick()
{
// Create a tween on the target
TweenScale.Begin(target, duration, Vector3.one * 0.01f);
}

In the preceding code, we scale down the target for the desired duration, towards 0.01f.

Save the script. Good. Now, we simply have to assign our variables in the Inspector view:

  1. Go back to Unity and select our Play button GameObject.
  2. Drag our UI Root | Main object in the DisappearOnClick Target field.

Great. Now, hit Unity’s play button. When you click the menu’s Play button, our main menu is scaled down to {0.01, 0.01, 0.01}, with the simple TweenScale.Begin() line!

Now that we’ve seen how to make a basic tween, let’s see how to add effects.

Tween effects

Right now, our tween is simple and linear. In order to add an effect to the tween, we first need to store it as UITweener, which is its parent class.

Replace lines of our OnClick() method by these to first store it and set an effect:

// Retrieve the new target's tween
UITweener tween =
TweenScale.Begin(target, duration, Vector3.one * 0.01f);
// Set the new tween's effect method
tween.method = UITweener.Method.EaseInOut;

That’s it. Our tween now has an EaseInOut effect. You also have the following tween effect methods:

 Learning NGUI for Unity

Perform the following steps:

  • BounceIn: Bouncing effect at the start of tween
  • BounceOut: Bouncing effect at the end of tween
  • EaseIn: Smooth acceleration effect at the start of tween
  • EaseInOut: Smooth acceleration and deceleration
  • EaseOut: Smooth deceleration effect at the end of tween
  • Linear: Simple linear tween without any effects

Great. We now know how to add tween effects through code. Now, let’s see how we can set event delegates through code.

You can set the tween’s ignoreTimeScale to true if you want it to always run at normal speed even if your Time.timeScale variable is different from 1.

Event delegates

Many NGUI components broadcast events, for which you can set an event delegate—also known as a callback method—executed when the event is triggered. We did it through the Inspector view by assigning the Notify and Method fields when buttons were clicked.

For any type of tween, you can set a specific event delegate for when the tween is finished. We’ll see how to do this through code. Before we continue, we must create our callback first. Let’s create a callback that loads a new scene.

The callback

Open our MenuManager.cs script, and add this static LoadGameScene() callback method:

public static void LoadGameScene()
{
//Load the Game scene now
Application.LoadLevel("Game");
}

Save the script. The preceding code requests to load the Game scene. To ensure Unity finds our scenes at runtime, we’ll need to create the Game scene and add both Menu and Game scenes to the build settings:

  1. Navigate to File | Build Settings.

  2. Click on the Add Current button (don’t close the window now).
  3. In Unity, navigate to File | New Scene.
  4. Navigate to File | Save Scene as…
  5. Save the scene as Game.unity.
  6. Click on the Add Current button of the Build Settings window and close it.
  7. Navigate to File | Open Scene and re-open our Menu.unity scene.

Ok, now that both scenes have been added to the build settings, we are ready to link our callback to our event.

Linking a callback to an event

Now that our LoadGameScene() callback method is written, we must link it to our event. We have two solutions. First, we’ll see how to assign it using code exclusively, and then we’ll create a more flexible system using NGUI’s Notify and Method fields.

Code

In order to set a callback for a specific event, a generic solution exists for all NGUI events you might encounter: the EventDelegate.Set() method. You can also add multiple callbacks to an event using EventDelegate.Add().

Add this line at the end of the OnClick() method of DisappearOnClick.cs:

// Set the tween's onFinished event to our LoadGameScene callback
EventDelegate.Set(tween.onFinished, MenuManager.LoadGameScene);

Instead of the preceding line, we can also use the tween-specific SetOnFinished() convenience method to do this. We’ll get the exact same result with fewer words:

// Another way to assign our method to the onFinished event
tween.SetOnFinished(MenuManager.LoadGameScene);

Great. If you hit Unity’s play button and click on our main menu’s Play button, you’ll see that our Game scene is loaded as soon as the tween has finished!

It is possible to remove the link of an existing event delegate to a callback by calling EventDelegate.Remove(eventDelegate, callback);.

Now, let’s see how to link an event delegate to a callback using the Inspector view.

Inspector

Now that we have seen how to set event delegates through code, let’s see how we can create a variable to let us choose which method to call within the Inspector view, like this:

 Learning NGUI for Unity

The method to call when the target disappears can be set any time without editing the code

The On Disappear variable shown in the preceding screenshot is of the type EventDelegate. We can declare it right now with the following line as a global variable for our DisappearOnClick.cs script:

// Declare an event delegate variable to be set in Inspector
public EventDelegate onDisappear;

Now, let’s change the OnClick() method’s last line to make sure the tween’s onFinished event calls the defined onDisappear callback:

// Set the tween's onFinished event to the selected callback
tween.SetOnFinished(onDisappear);

Ok. Great. Save the script and go to Unity. Select our main menu’s Play button: a new On Disappear field has appeared.

Drag UI Root—which holds our MenuManager.cs script—in the Notify field. Now, try to select our MenuManager | LoadGameScene method. Surprisingly, it doesn’t appear, and you can only select the script’s Exit method… why is that?

That is simply because our LoadGameScene() method is currently static. If we want it to be available in the Inspector view, we need to remove its static property:

  1. Open our MenuManager.cs script.

  2. Remove the static keyword from our LoadGameScene() method.

Save the script and return to Unity. You can now select it in the drop-down list:

 Learning NGUI for Unity

Great! We have set our callback through the Inspector view; the Game scene will be loaded when the menu disappears.

Now that we have learned how to assign event delegates to callback methods through code and the Inspector view, let’s see how to assign keyboard keys to user interface elements.

Keyboard keys

In this section, we’ll see how to add keyboard control to our UI. First, we’ll see how to bind keys to buttons, and then we’ll add a navigation system using keyboard arrows.

UIKey binding

The UIKey Binding component assigns a specific key to the widget it’s attached to. We’ll use it now to assign the keyboard’s Escape key to our menu’s Exit button:

  1. Select our UI Root | Main | Buttons | Exit GameObject.

  2. Click the Add Component button in the Inspector view.
  3. Type key with your keyboard to search for components.
  4. Select Key Binding and hit Enter or click on it with your mouse.

Let’s see its available parameters.

Parameters

We’ve just added the following UIKey Binding component to our Exit button, as follows:

 Learning NGUI for Unity

The newly attached UIKey Binding component has three parameters:

  • Key Code: Which key would you like to bind to an action?
  • Modifier: If you want a two-button combination. Select on the four available modifiers: Shift, Control, Alt or None.
  • Action: Which action should we bind to this key? You can simulate a button click with PressAndClick, a selection with Select, or both with All.

Ok, now, we’ll configure it to see how it works.

Configuration

Simply set the Key Code field to Escape. Now, hit Unity’s play button. When you hit the Escape key of our keyboard, it reacts as if the Exit button was pressed!

We can now move on to see how to add keyboard and controller navigation to the UI.

UIKey navigation

The UIKey Navigation component helps us assign objects to select using the keyboard arrows or controller directional-pad. For most widgets, the automatic configuration is enough, but we’ll need to use the override parameters in some cases to have the behavior we need.

The nickname input field has neither the UIButton nor the UIButton Scale components attached to it. This means that there will be no feedback to show the user it’s currently selected with the keyboard navigation, which is a problem. We can correct this right now.

Select UI Root | Options | Nickname | Input, and then:

  1. Add the Button component (UIButton) to it.

  2. Add the Button Scale component (UIButton Scale) to it.
  3. Center Pivot of UISprite (middle bar + middle bar).
  4. Reset Center of Box Collider to {0, 0, 0}.

The Nickname | Input GameObject should have an Inspector view like this:

 Learning NGUI for Unity

Ok. We’ll now add the Key Navigation component (UIKey Navigation) to most of the buttons in the scene. In order to do that, type t:uibutton in the Hierarchy view’s search bar to display only GameObjects with the UIButton component attached to them:

 Learning NGUI for Unity

Ok. With the preceding search filter, select the following GameObjects:

 Learning NGUI for Unity

Now, with the preceding selection, follow these steps:

  1. Click the Add Component button in the Inspector view.

  2. Type key with your keyboard to search for components.
  3. Select Key Navigation and hit Enter or click on it with your mouse.

We’ve added the UIKey Navigation component to our selection. Let’s see its parameters.

Parameters

We’ve just added the following UIKey Navigation component to our objects:

 Learning NGUI for Unity

The newly attached UIKey Navigation component has four parameter groups:

  1. Starts Selected: Is this widget selected by default at the start?

  2. Select on Click: Which widget should be selected when this widget is clicked on — or the Enter key/confirm button has been pressed? This option can be used to select a specific widget when a new page is displayed.
  3. Constraint: Use this to limit the navigation movement from this widget:
    • None: The movement is free from this widget
    • Vertical: From this widget, you can only go up or down
    • Horizontal: From this widget, you can only move left or right
    • Explicit: Only move to widgets specified in the Override
  4. Override: Use the Left, Right, Up, and Down fields to force the input to select the specified objects. If the Constraint parameter is set to Explicit, only widgets specified here can be selected. Otherwise, automatic configuration still works for fields left to None.

Summary

This article thus has given an introduction to how C# is used in Unity.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here