UI Components

Taking a look at the common apps you might use, I bet that you can spot UI widgets without necessarily knowing what they are. They aren't specific to games, every application probably uses a few widgets. What does UI stand for? What do UI widgets do? Oh so many questions!

Widgets, oh, my!

UI is an abbreviation that stands for user interface. You know, things that are on the screen. This include items like: labels, buttons, menus, sliders and views. Cocos2d-x provides a set of UI widgets to make it simple to add these controls to your projects. It may sound trivial, but a lot goes in to creating a core class like a Label. There are so many aspects of just this one. Could you imagine having to write your own custom widget set? Don't worry, your needs are covered!

Label

Cocos2d-x provides a Label object that can create labels using true type, bitmap or the built-in system font. This single class can handle all your Label needs.

Label BMFont

BMFont is a label type that uses a bitmap font. The characters in a bitmap font are made up of a matrix of dots. It is very fast and easy to use, but not scalable as it requires a separate font for each size character. Each character in a Label is a separate Sprite. This means that each character can be rotated, scaled, tinted, have a different anchor point and/or most any other property changed.

Creating a BMFont label requires two files: a .fnt file and an image representation of each character in .png format. If you are using a tool like Glyph Designer these files are created automatically for you. Creating a Label object from a bitmap font:

auto myLabel = Label::createWithBMFont("bitmapRed.fnt", "Your Text");

All of the characters in the string parameter should be found in the provided .fnt file, otherwise they won't be rendered. If you render a Label object and it is missing characters, make sure they exist in your .fnt file.

Label TTF

True Type Fonts are different from the bitmap fonts we learned about above. With true type fonts the outline of the font is rendered. This is convenient as you do not need to have a separate font file for each size and color you might wish to use. Creating a Label object that uses a true type font is easy. To create one you need to specify a .ttf font file name, text string and a size. Unlike BMFont, TTF can render size changes without the need for a separate font files. Example, using a true type font:

auto myLabel = Label::createWithTTF("Your Text", "Marker Felt.ttf", 24);

Although it is more flexible than a bitmap font, a true type font is slower to render and changing properties like the font face and size is an expensive operation.

If you need several Label objects from a true type font that all have the same properties you can create a TTFConfig object to manage them. A TTFConfig object allows you to set the properties that all of your labels would have in common. You can think of this like a recipe where all your Label objects will use the same ingredients.

You can create a TTFConfig object for your Labels in this way:

// create a TTFConfig files for labels to share
TTFConfig labelConfig;
labelConfig.fontFilePath = "myFont.ttf";
labelConfig.fontSize = 16;
labelConfig.glyphs = GlyphCollection::DYNAMIC;
labelConfig.outlineSize = 0;
labelConfig.customGlyphs = nullptr;
labelConfig.distanceFieldEnabled = false;

// create a TTF Label from the TTFConfig file.
auto myLabel = Label::createWithTTF(labelConfig, "My Label Text");

A TTFConfig can also be used for displaying Chinese, Japanese and Korean characters.

Label SystemFont

SystemFont is a label type that uses the default system font and font size. This is a font that is meant not to have its properties changed. You should think of it as system font, system rules. Creating a SystemFont label:

auto myLabel = Label::createWithSystemFont("My Label Text", "Arial", 16);

Label Effects

After you have your Label objects on screen you might want to make them a bit prettier. Perhaps they look flat or plain. Thankfully you don't have to create your own custom fonts! Label objects can have effects applied to them. Not all Label objects support all effects. Some effects include shadow, outline and glow. You can apply one or more effects to a Label object easily:

Label with a shadow effect:

auto myLabel = Label::createWithTTF("myFont.ttf", "My Label Text", 16);

// shadow effect is supported by all Label types
myLabel->enableShadow();

Label with a outline effect:

auto myLabel = Label::createWithTTF("myFont.ttf", "My Label Text", 16);

// outline effect is TTF only, specify the outline color desired
myLabel->enableOutline(Color4B::WHITE, 1));

Label with a glow effect:

auto myLabel = Label::createWithTTF("myFont.ttf", "My Label Text", 16);

// glow effect is TTF only, specify the glow color desired.
myLabel->enableGlow(Color4B::YELLOW);

We are all probably familiar with what a menu is. We see these in every application we use. In your game you would probably use a Menu object to navigate through game options. Menus often contain buttons like Play, Quit, Settings and About, but could also contain other Menu objects for a nested menu system. A Menu object is a special type of Node object. You can create an empty Menu object as a place holder for your menu items:

auto myMenu = Menu::create();

As we described options above of Play, Quit, Settings and About, these are your menu items. A Menu without menu items makes little sense. Cocos2d-x offers a variety of ways to create your menu items including by using a Label object or specifying an image to display. Menu items usually have two possible states, a normal and a selected state. When you tap or click on the menu item a callback is triggered. You can think of this as a chain reaction. You tap/click the menu item and it runs the code you specified. A Menu can have just a single item or many items.

// creating a menu with a single item

// create a menu item by specifying images
auto closeItem = MenuItemImage::create("CloseNormal.png", "CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

auto menu = Menu::create(closeItem, NULL);
this->addChild(menu, 1);

A menu can also be created by using a vector of MenuItem objects:

// creating a Menu from a Vector of items
Vector<MenuItem*> MenuItems;

auto closeItem = MenuItemImage::create("CloseNormal.png", "CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

MenuItems.pushBack(closeItem);

/* repeat for as many menu items as needed */

auto menu = Menu::createWithArray(MenuItems);
this->addChild(menu, 1);

If you run the sample code for this chapter you will see a Menu containing Label objects for MenuItems:

Lambda functions as Menu callbacks

Above we just learned that when you click a menu item it triggers a callback. C++11 offers lambda functions and therefore Cocos2d-x takes full advantage of them! A lambda function is a function you write inline in your source code. Lambdas are also evaluated at runtime instead of compile time.

A simple lambda:

// create a simple Hello World lambda
auto func = [] () { cout << "Hello World"; };

// now call it someplace in code
func();

Using a lambda as a MenuItem callback:

auto closeItem = MenuItemImage::create("CloseNormal.png", "CloseSelected.png",
[&](Ref* sender){
    // your code here
});

Buttons

I doubt that we need to explain buttons much. We all know them as those things we click on to make something happen in our games. Perhaps you might use a button to change scenes or to add Sprite objects into your game play. A button intercepts a touch event and calls a predefined callback when tapped. A Button has a normal and selected state. The appearance of the Button can change based upon it's state. Creating a Button and defining its callback is simple:

#include "ui/CocosGUI.h"

auto button = Button::create("normal_image.png", "selected_image.png", "disabled_image.png");

button->setTitleText("Button Text");

button->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
        switch (type)
        {
                case ui::Widget::TouchEventType::BEGAN:
                        break;
                case ui::Widget::TouchEventType::ENDED:
                        std::cout << "Button 1 clicked" << std::endl;
                        break;
                default:
                        break;
        }
});

this->addChild(button);

As you can see in the above example we specify a .png image for each of the possible states the button can be in. A Button is made up of 3 graphics that might look like this:

On screen a Button might look like this:

CheckBox

We are all used to filling out checkboxes on paper forms like job applications and rental agreements. You can also have checkboxes in your games. Perhaps, you want to have the ability for your player to make a simple yes or no choice. You might also hear this referred to as a binary choice (0 and 1). A CheckBox permits the user to make this type of choice. There are 5 different states a Checkbox can have: normal, selected and disabled. It is simple to create a CheckBox:

#include "ui/CocosGUI.h"

auto checkbox = CheckBox::create("check_box_normal.png",
                                 "check_box_normal_press.png",
                                 "check_box_active.png",
                                 "check_box_normal_disable.png",
                                 "check_box_active_disable.png");

checkbox->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
        switch (type)
        {
                case ui::Widget::TouchEventType::BEGAN:
                        break;
                case ui::Widget::TouchEventType::ENDED:
                        std::cout << "checkbox 1 clicked" << std::endl;
                        break;
                default:
                        break;
        }
});

this->addChild(checkbox);

As you can see in the above example we specify a .png image for each of the possible states the Checkbox can be in. Since there are 5 possible states that a CheckBox can be in, it is up 5 graphics, one for each of its states. Example graphics:

On screen a Checkbox might look like this:

LoadingBar

Have you ever played a game where you had to wait while it loaded up all the content it needed? It probably showed you a bar, filling in as it made progress accomplishing its task. This is often referred to as a progress bar, status bar or a loading bar. Creating a LoadingBar:

#include "ui/CocosGUI.h"

auto loadingBar = LoadingBar::create("LoadingBarFile.png");

// set the direction of the loading bars progress
loadingBar->setDirection(LoadingBar::Direction::RIGHT);

this->addChild(loadingBar);

In the above example a loading bar is created and we set the direction it should fill towards as progress is made. In this case to the right direction. However, you probably need to change the percentage of the LoadingBar. This is easily done:

#include "ui/CocosGUI.h"

auto loadingBar = LoadingBar::create("LoadingBarFile.png");
loadingBar->setDirection(LoadingBar::Direction::RIGHT);

// something happened, change the percentage of the loading bar
loadingBar->setPercent(25);

// more things happened, change the percentage again.
loadingBar->setPercent(35);

this->addChild(loadingBar);

As you can see in the above example we specify a .png image for the LoadingBar objects texture:

On screen a LoadingBar might look like this:

ScrollView

Let’s say you have a menu full of options for the player to choose from. Uh, oh, you can;t fit them all in a column on the screen. Do you get rid of any? No! You use a ScrollView. Just as it sounds you can create a ScrollView to navigate top to bottom and/or left to right in a Scene. To create a ScrollView:

#include "ui/CocosGUI.h"

auto scrollView = cocos2d::ui::ScrollView::create();

In the above example we create a ScrollView. By default this ScrollView defaults to scrolling vertically. You can also scroll horzontally or both vertically and horizontally. Examples:

#include "ui/CocosGUI.h"

// creates a vertically scrollable ScrollView 
auto scrollView = cocos2d::ui::ScrollView::create();

// this is also the same as the above with a redundant
// 
auto scrollView = cocos2d::ui::ScrollView::create();

Slider

Sometimes it is necessary to change a value slightly. Perhaps you have a character and you want to allow the player to adjust the strength of attacking an enemy. A Slider allows users to set a value by moving an indicator. To create a Slider:

#include "ui/CocosGUI.h"

auto slider = Slider::create();
slider->loadBarTexture("Slider_Back.png"); // what the slider looks like
slider->loadSlidBallTextures("SliderNode_Normal.png", "SliderNode_Press.png", "SliderNode_Disable.png");
slider->loadProgressBarTexture("Slider_PressBar.png");

slider->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
        switch (type)
        {
                case ui::Widget::TouchEventType::BEGAN:
                        break;
                case ui::Widget::TouchEventType::ENDED:
                        std::cout << "slider moved" << std::endl;
                        break;
                default:
                        break;
        }
});

this->addChild(slider);

As you can see in the above example we specify a .png image for each of the possible states the slider can be in. A Slider is made up of 5 graphics that might look like this:

On screen a Slider might look like this:

TextField

What if you wanted the player of your game to type in a special name to call the main character? Where would they type it into? Yes, a text field, of course. A TextField widget is used for inputting text. It supports touch event, focus, percent positioning and percent content size. To create a TextField widget:

#include "ui/CocosGUI.h"

auto textField = TextField::create("","Arial",30);

textField->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
                std::cout << "editing a TextField" << std::endl;
});

this->addChild(textField);

In this example a TextField is created and a callback specified.

TextField objects are versatile and can meet all of your input needs. Would you like the user to enter a secret password? Do you need to limit the number of characters a user can input? TextField objects have this all built-it and much more! Let's take a look at an example:

#include "ui/CocosGUI.h"

auto textField = TextField::create("","Arial",30);

// make this TextField password enabled
textField->setPasswordEnabled(true);

// set the maximum number of characters the user can enter for this TextField
textField->setMaxLength(10);

textField->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type){
                std::cout << "editing a TextField" << std::endl;
});

this->addChild(textField);

On screen a TextField might look like this:

When you are editing a TextField, the onscreen keyboard comes up: