标签(Label)

是一个 **Label** 对象,可以使用位图字体,TrueType 字体,系统字体创建标签。

注意,如果在使用中文时乱码,可以在.cpp文件中添加

  1. #ifdef WIN32
  2. #pragma execution_character_set("utf-8")
  3. //主体代码
  4. #endif

BMFont格式

BMFont 是一个使用位图字体创建的标签类型,位图字体中的字符由点阵组成。使用这种字体标签性能非常好,但是不适合缩放。由于点阵的原因,缩放会导致失真。标签中的每一个字符都是一个单独的 Sprite,也就是说精灵的属性(旋转,缩放,着色等)控制都适用于这里的每个字符。

创建 BMFont 标签需要两个文件:.fnt 文件和 .png 文件。

使用位图字体创建标签:

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

五. UI组件 - 图1

不过.fnt虽然具有渲染快速的优点,不过缺点是制作繁琐,中文资源不足,大多数情况下,使用TTF即可,而且TTF缩放也不会失真

TTF格式

要创建这种标签,需要指定 .ttf 字体文件名,文本字符串和字体大小。

使用 TrueType 字体创建标签:

auto myLabel = Label::createWithTTF("Your Text", "Marker Felt.ttf", 24); //如果想使用自己的.ttf字体文件,需要将下载得到的文件放在工程目录的\Resources\fonts下

五. UI组件 - 图2

如果您需要具有相同属性的多个 Label 对象,那可以创建一个 TTFConfig 对象来统一配置,TTFConfig 对象允许你设置所有标签的共同属性。

通过以下方式创建一个 TTFConfig 对象:

// 创建 TTFConfig 文件,优点是,更改它即可一并更改所有引用此对象的Label
TTFConfig labelConfig;
labelConfig.fontFilePath = "fonts/Marker Felt.ttf";
labelConfig.fontSize = 20;
labelConfig.outlineSize = 2;
labelConfig.underline = true;

// 为创建的TTF Label 使用 labelConfig
auto myLabel = Label::createWithTTF(labelConfig, "My Label Text");

五. UI组件 - 图3

SystemFont

SystemFont 是一个使用系统默认字体,默认字体大小的标签类型。

使用系统字体创建标签:

auto myLabel = Label::createWithSystemFont("My Label Text", "Arial", 16);  //有的系统中如果要使用“黑体”,可能对应的是“SimHei” ,微软雅黑可能是“Microsoft YaHei”,而不是中文,不过有的系统可以直接使用中文

五. UI组件 - 图4

标签效果

在屏幕上有标签后, Label 对象就可以对标签应用效果,包括阴影,描边,发光。

阴影效果:

// 首先创建一个标签
auto myLabel = Label::createWithTTF("myFont.ttf", "My Label Text", 16);

// 启动阴影,该函数有三个参数Color4B(R,G,B,A),Size(大小,偏移值),以及一个模糊度数值,如果不填,则会有默认参数(为黑色)
myLabel->enableShadow(Color4B(0,0,0,125),Size(3,-2), 10);

五. UI组件 - 图5

描边效果:

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

// 参数为颜色以及描边宽度
myLabel->enableOutline(Color4B::WHITE, 1));

五. UI组件 - 图6

发光效果:

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

// 参数只有一个,发光颜色
myLabel->enableGlow(Color4B::YELLOW);

五. UI组件 - 图7



菜单(Menu)

菜单项(MenuItem)

  1. 文本菜单项 ```cpp MenuItemFont:: setFontName(“字体名称”); MenuItemFont:: setFontSize(大小); MenuItemFont item1 = MenuItemFont::create(名称, 回调函数); MenuItemAtlasFont item2 = MenuItemAtlasFont::create(名称,路径,大小x,大小y,’ ‘,回调函数);

//利用已经创建好的Label来创建菜单
auto buttonLabel1 = Label::createWithTTF(“fonts/TencentSans-W7.ttf”,”Place”,24); auto button1 = MenuItemLabel::create(buttonLabel1, = { Director::getInstance()->pushScene(Action1::createScene(PLACE_TAG)); });


2. 精灵菜单项
2. 开关菜单项
```cpp
auto toggleMenuuItem = MenuItemToggle::createWithCallback(回调函数,开启状态,关闭状态,NULL);

创建菜单

我们使用菜单浏览游戏选项,更改游戏设置。菜单通常包含开始,退出,设置,关于等项,菜单当然也可以包含子菜单。Cocos2dX 提供 **Menu** 对象支持菜单功能,_Menu_ 对象是一种特殊的 _节点Node_ 对象

创建一个菜单用于添加菜单项:

auto myMenu = Menu::create();

像我们刚才提到的一个菜单,总会有一些菜单项,比如开始,退出,设置等,没有菜单项的菜单没有存在的意义。Cocos2d-x 提供了一些方法来创建菜单项,比如使用 Label 对象,或是使用一张图像。菜单项一般有正常状态和选择状态。菜单项显示时是正常状态,当你点击它时变为选择状态,同时点击菜单还会触发一个回调函数。

使用图像创建菜单:

// 创建一个菜单,并传入Item

// 用MenuItemImage的方式创建,参数有点击前的图片,点击后的图片,回调函数
auto closeItem = MenuItemImage::create("CloseNormal.png", "CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
// 其余的菜单物体有MenuItemLabel, MenuItemFont等

//创建一个MenuItemFont
auto myLabel = Label::createWithTTF("Cancel", "fonts/Marker Felt.ttf", 20);

//创建一个MenuItemLabel
auto changeScene = MenuItemFont::create("Go To The Level_01", CC_CALLBACK_0(HelloWorld::goToLevel_01, this));
auto cancelMenuItem = MenuItemLabel::create(myLabel, CC_CALLBACK_0(HelloWorld::goToLevel_01, this));
cancelMenuItem->setPositionY(-30);

//添加进我们的菜单中,注意,菜单的最后一个参数不是菜单Item节点,默认情况下,传入NULL即可
auto myMenu = Menu::create(closeItem, changeScene, cancelMenuItem, NULL);

this->addChild(myMenu, 1);

还可以使用 MenuItem 的一个 vector 创建菜单:

// 创建一个保存MenuItem*的Vector集合
Vector<MenuItem*> MenuItems;

auto closeItem = MenuItemImage::create("CloseNormal.png", "CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
//menuCloseCallback中存在一个传参 Ref* pSender 可以在函数中或者按钮参数
//如 MenuItem *item = (MenuItem*)pShender;

MenuItems.pushBack(closeItem);  //用pushBack可以让菜单Item排序按照加载顺序排列

// 注意创建时,需要使用createWithArray而不是create
auto menu = Menu::createWithArray(MenuItems);
this->addChild(menu, 1);

image.png

使用匿名函数

当您点击菜单项时会触发一个回调函数。C++ 11 支持了 匿名函数,所以你可以在回调方法处,使用匿名函数,这样能让代码看起来更简洁,同时不会有额外的性能开销。

一个简单的 lambda 表达式:

auto func = [] () { cout << "Hello World"; };

// 之后可以在任意地方调用该函数(当然,一般我们用匿名函数的时候,是抱着不会二次调用的情况下使用的)
func();

使用 lambda 表达式作为菜单项的回调函数:

auto changeScene = MenuItemFont::create("Go To The Level_01", [&](Ref* sender) {
    clickCount++;    //我们让每次点击的时候,计数参数++
    string clickStr = "Click time: " + to_string(clickCount);
    clickLabel->setString(clickStr); //更新当前点击的次数

    auto level_01_Scene = Level_01::create();
    Director::getInstance()->pushScene(level_01_Scene);
});//替换了原先我们指定的CC_CALLBACK_0(HelloWorld::goToLevel_01, this)部分
//这样做的好处是,我们不需要再定义一个函数,再在.cpp中完善函数体,如果这个函数就单单只会在这一个地方调用的话

关于匿名函数的参数捕获形式,更多内容可以参考cocos2d3.10 简单引用lambda表达式用作回调函数
image.png



按钮(Button)

创建按钮

按钮的关键在于,点击后会有什么响应。按钮会拦截点击事件,事件触发时调用事先定义好的回调函数。按钮有一个正常状态normal,一个选择状态selected,还有一个不可点击状态disabled,按钮的外观可以根据这三个状态而改变。Cocos2d-x 提供 **Button** 对象支持按钮功能,创建一个按钮并定义一个回调函数很简单,记得在操作的时候要有头文件包含: #include "ui/CocosGUI.h",以及命名空间using namespace cocos2d::ui;

#include "ui/CocosGUI.h"
using namespace cocos2d::ui;
//按钮在创建时可以传入三个参数,也可以传入一个,如果只传一个,则按钮点击样式默认为点中时放大,放开点击后回复大小
auto button = Button::create("normal_image.png", "selected_image.png", "disabled_image.png");
//auto button = Button::create("HelloWorld.png");

button->setTitleText("Button Text");    //这段文字会显示在按钮之上
button->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));

button->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
    // 这是一段匿名函数
    log("按钮点击的事件监听器");

});

this->addChild(button);

可以看到,我们为按钮的每个状态都指定了一个.png图像:

五. UI组件 - 图10 五. UI组件 - 图11 五. UI组件 - 图12 五. UI组件 - 图13 五. UI组件 - 图14

在屏幕显示的时候,同一个时刻只能看到一个状态,正常显示状态像这样:

五. UI组件 - 图15
如果我们不想在按钮处使用匿名函数,那么我们可以创建一个函数,但是一定要注意,函数需要包括按钮必要的传参参数

void HelloWorld::logInfo(Ref* pSender, Widget::TouchEventType type) {
    log("这是一个打印函数");
}
auto button = Button::create("HelloWorld.png");
button->setTitleText("Button Text");
button->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));

//在这里使用回调函数的方式增加我们的自定义函数
button->addTouchEventListener(CC_CALLBACK_2(HelloWorld::logInfo, this));


输入框(EditBox)

Cocos2d-x 提供 **EditBox** 满足这种需求。它支持触摸事件,焦点,定位内容百分比等。

创建一个文本框:

//使用输入框之前,请加上这三句代码
#include "cocos-ext.h"
using namespace cocos2d::ui;
USING_NS_CC_EXT;


auto editBoxSize = Size(400, 40);    //创建一个可用于编辑的Size变量
auto editName = EditBox::create(editBoxSize, "inputBox.png");  //构造函数的参数为Size大小,以及一张背景图
editName->setPosition(Point(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2 + 50));    //设置位置
editName->setFont("Arial", 20); //设置字体以及大小(目前只能支持系统自带字体)
// editName->setFontSize(20); 注意,如果不指定字体,直接设置大小将不会生效,不过可以通过修改引擎源码解决,或者,直接用系统最常用的Arial字体就好
editName->setFontColor(Color3B::RED);    //输入的字体颜色
editName->setPlaceHolder("Please enter your name"); //当未输入任何内容时,默认显示的内容,一单输入内容后将会被替换
editName->setPlaceholderFontColor(Color3B::WHITE); //设置上一行代码的字体颜色
editName->setMaxLength(8);    //设置最大可输入长度

this->addChild(editName);

这个例子中,创建了一个 EditBox

提供的文本框对象,是多功能的,能满足所有的输入需求,比如用户密码的输入,限制用户可以输入的字符数等等!

如果想要这是一个密码输入框,例子:

editPassword->setInputFlag(ui::EditBox::InputFlag::PASSWORD);


用户登录实例

首先,我们需要的是两个输入框

auto editBoxSize = Size(400, 40); //确定输入框的大小

auto editName = ui::EditBox::create(editBoxSize, "inputBox.png");
editName->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2 + 80));
editName->setFont("Arial", 20);
editName->setFontColor(Color3B::RED);
editName->setPlaceHolder("Please enter your name");
editName->setPlaceholderFontColor(Color3B::WHITE);
editName->setMaxLength(16);


this->addChild(editName);

auto editPassword = ui::EditBox::create(editBoxSize, "inputBox.png");
editPassword->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2 + 40));
editPassword->setFont("Arial", 20);
editPassword->setFontColor(Color3B::RED);
editPassword->setPlaceHolder("Please enter your password");
editPassword->setPlaceholderFontColor(Color3B::WHITE);
editPassword->setMaxLength(16);
editPassword->setInputFlag(ui::EditBox::InputFlag::PASSWORD);

this->addChild(editPassword);

光有输入框还不行,我们需要一个按钮

auto loginButton = ui::Button::create("next.png");
loginButton->setPosition(Vec2(origin.x + visibleSize.width / 2 + 150, origin.y + visibleSize.height / 2-20));
loginButton->setScale(0.4f);
//注意匿名函数的参数
loginButton->addTouchEventListener([=](Ref* pSender, ui::Widget::TouchEventType type) {

    //这一步判断,当触碰事件类型type为触碰结束时执行
    //更多关于监听事件,以及交互操作会在之后补充

    if (type == ui::Widget::TouchEventType::ENDED) {

        auto name = editName->getText();    //这一步可以获取我们输入在输出框中的字符串
        auto password = editPassword->getText();

        if (name == nullptr || password == nullptr)
            return;

        if(strcmp(name,"root")==0 &&
           strcmp(password, "123456")==0) { //strcmp比较函数,会在相同时返回0
            log("密码正确");
            loginSuccessful();    //登录函数,我们可以写一个新的场景
        }
        else {
            log("密码或账号错误");
        }
    }

});

this->addChild(loginButton, 1);
void HelloWorld::loginSuccessful() {
    auto scene = MyPage::createScene();        //跳转到新的场景以验证登录
    Director::getInstance()->pushScene(scene);
}

image.pngimage.pngimage.png



进度条(LoadingBar)

如果你经常玩游戏,那肯定见过一个情景:屏幕上显示了一个进度条,提示资源正在加载中,这个条表示资源加载的进度。Cocos2d-x 提供 **LoadingBar** 对象支持进度条。

创建一个进度条:

#include "ui/CocosGUI.h"

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

// 设置进度条的方向
loadingBar->setDirection(LoadingBar::Direction::RIGHT);

this->addChild(loadingBar);

上面的例子,我们创建了一个进度条,设置了当进度增加时,进度条向右填充。

在进度的控制中,你肯定需要改变进度条的进度. 示例:

#include "ui/CocosGUI.h"

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

// 改变进度条的进度百分比
loadingBar->setPercent(25);


this->addChild(loadingBar);

在屏幕上一个满进度的进度条是这样的:

五. UI组件 - 图19


或者,也可以为我们的进度条设置一个背景框

auto loadingBarPosition = Vec2(origin.x + visibleSize.width / 2, + 80); //用于创建时的参数
auto loadingBarSize = Size(400, 40);
//创建进度条的背景
auto loadingBG = Sprite::create("PB_border.png");  //背景框可以使用Sprite
loadingBG->setPosition(loadingBarPosition); 
loadingBG->setContentSize(loadingBarSize);
loadingBG->setAnchorPoint(Point(0.5, 0.5)); //为了便于我们将进度条背景与进度条对其,锚点可以设置为几何中心

//创建进度条
auto loadingBar = LoadingBar::create("LoadingBarFile.png"); //使用LoadingBar创建
loadingBar->setDirection(LoadingBar::Direction::LEFT); //进度条方向为从左向右
loadingBar->setPosition(Vec2(loadingBarSize.width / 2, loadingBarSize.height / 2)); //居中在背景框中
loadingBar->setContentSize(loadingBarSize);
loadingBar->setScale(1.9);
loadingBar->setAnchorPoint(Point(0.5,0.5));

// 改变进度条的进度百分比
loadingBar->setPercent(90);

//别忘了将背景框添加到场景层中,为了便于对齐,可以将loadingBar加载到loadingBG背景框上,也便于后期统一处理
this->addChild(loadingBG);
loadingBG->addChild(loadingBar);

大致效果:
image.png


而进一步使用进度条,需要介绍Cocos中的计时器部分,进度条的案例在下一章介绍