Cocos2d-x游戏开发实战精解
上QQ阅读APP看书,第一时间看更新

3.1 在Cocos2d-x中显示一行文字

实际上,在上一章的内容中就曾经使用Label控件在屏幕上显示过一串数字。在Cocos2d-x中要显示文字就需要用到Label控件。在3.x版本的Cocos2d中,舍弃了之前版本所使用的LabelTTF、LabelAtlas、LabelBMFont 3个用于显示文字的类,而使用一个新类Label取代。可想而知,Label实际上就是对之前3个类进行重新封装并统一渲染。

提示:实际上老版本的内容在3.x版本中依然是可以使用的。

下面是在Cocos2d-x中显示文字的一个例子,具体完整项目可在源文件本章目录下找到项目ChapterThree01查看。

【范例3-1】在Cocos2d-x中显示文字。

01 auto label1 = Label::create("this is the first label","Arial",36,
02                       Size::ZERO,TextHAlignment::LEFT,TextVAlignment::TOP);  //创建标签
03      label1->setPosition(210, 310);                                          //设置标签位置
04      addChild(label1);                                                       //加入到场景中
05      //通过TTFConfig在标签中使用自定义字体
06      TTFConfig ttfconfig("fonts/chunkmuffinhollowwide.ttf", 36);                     //创建TTFConfig对象
07      auto label2 = Label::createWithTTF(ttfconfig,"this is the second label");       //创建标签
08      label2->setPosition(270,250);                                                   //设置标签位置
09      addChild(label2);                                                               //将标签加入到场景中
10      //使用createWithTTF方法创建使用自定义字体的标签
11      auto label3 = Label::createWithTTF("this is the third label","fonts/Marker Felt.ttf",36);
12      label3->setPosition(200, 190);                                       //设置标签位置
13      addChild(label3);                                                   //将标签加入到场景中
14      //为标签加入阴影和边框效果
15      auto label4 = Label::createWithTTF("this is the fourth label", "fonts/Marker Felt.ttf", 36);
16      label4->setPosition(280,130);                                        //设置标签位置
17      label4->enableShadow(Color4B::GREEN, Size(5, 5));    //设置阴影效果
18      label4->enableOutline(Color4B::RED, 3);              //设置边框效果
19      addChild(label4);                                                   //将标签加入到场景中
20      //创建带发光效果的标签
21      auto label5 = Label::createWithTTF("this is the fifth label", "fonts/Marker Felt.ttf", 36);
22      label5->setPosition(200, 70);                        //设置标签位置
23      label5->enableGlow(Color4B::GREEN);                  //设置光效
24      addChild(label5);                                    //将标签加入到场景中

运行之后的效果如图3-1所示。

图3-1 在屏幕上显示不同效果的标签

在一般情况下想要在屏幕上输出一行文字只需要按照第01~04行的方法来创建一个标签,然后再将它加入到场景中去就可以了。最简单的创建标签的方法如范例第01~02行所示,其中create方法的6个参数含义分别是:

❑标签中所显示文字的内容。

❑标签字体。

❑标签内容字体大小。

❑标签尺寸。

❑标签中文字在横向和纵向的对齐方式。

这看上去有点复杂,实在配不上“最简单”的创建方法,所以一般在使用时可以进一步简化,仅保留前3项参数,比如本范例第01行就可以改写成:

auto label1 = Label::create("this is the first label","Arial",36);

显示的文字如图3-1第一行所示,所以说在Cocos2d中显示文字是非常容易的。然而不能忘记的是,学习Cocos2d的目的主要还是为了做游戏,这样单调的文字自然是远远不能适应游戏的需要,所以就需要在标签中使用更加个性化的字体。

在Cocos2d 2.x版本中,可以使用LabelTTF类创建标签来使用TTF格式的字体,然而在Cocos2d 3.x中由于LabelTTF被取消(实际仍然可以使用),就要考虑使用其他办法来显示自定义字体。目前主要有两种方法:

❑通过TTFConfig配置来创建,如范例第06~09行所示;

❑使用createWithTTF方法创建使用TTF字体的标签,如范例第11~13行所示。

这两种方法从本质上来说都是从资源目录下读取TTF格式的字体文件,可以在项目目录下找到Resources|fonts文件夹,将从网上下载的字体文件存放在这里。

为了让字体具有更强大的视觉冲击力,还可以给文字加入阴影和边框以及外发光的效果。如范例第17行就是给标签加入阴影,其中Color4B::GREEN是阴影的颜色而Size(5, 5)是阴影相对于文字的相对位置。第18行则是用来设置文字边框的,两个参数分别用来设置边框颜色和宽度。第23行为文字加入的外发光效果只有一个参数,那就是光效的颜色。

提示:需要注意的是外发光和边框这两种效果是不能并存的。

这里还要提醒各位读者,在Cocos2d中直接使用中文是无法正确显示的,比如笔者将范例中的代码做一个简单的修改,将显示的内容更换成“欢迎学习Cocos2d”就会显示出如图3-2所示的乱码。

图3-2 在Cocos2d中直接使用中文会造成乱码

这真是一个忧伤的问题,毕竟作为中国的开发者今后主要面对的还是国内的用户,尤其是网游行业那么高的利润要是因为不支持中文扑街,那就实在是有点太倒霉了。所以,这个问题一定要解决,解决的方法有以下几种。

(1)第一种是通过转换为utf-8编码的方式显示出来,需要新建一个用于转换中文到对应utf-8编码的FontToUTF8方法支持,该方法具体实现如下:

【范例3-2】FontToUTF8方法的实现。

01 char* HelloWorld::FontToUTF8(const char* font)
02      {
03              int len = MultiByteToWideChar(CP_ACP, 0, font, -1, NULL, 0);
04              wchar_t* wstr = new wchar_t[len + 1];
05              memset(wstr, 0, len + 1);
06              MultiByteToWideChar(CP_ACP, 0, font, -1, wstr, len);
07              len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, 
                NULL);
08              char* str = new char[len + 1];
09              memset(str, 0, len + 1);
10              WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
11              if (wstr)delete[] wstr;
12              return str;
13      }

然后再运行如下代码将中文标签加入到屏幕中去。

auto label = Label::create(HelloWorld::FontToUTF8("欢迎学习Cocos2d"), "Arial",36);
label->setPosition(320,300);
this->addChild(label);

这种方法仅仅依靠代码实现而不需要进行额外的设置,但是效果并不稳定,容易产生某些错误或者依然乱码,因此并不推荐。

(2)这里再介绍一种方法,是在上一章中曾经提到过的引入iconv库实现中文显示的方法。在使用iconv库时,往往需要对Visual Studio进行一些设置,这里笔者介绍一种方法可以不借助这些设置直接引入iconv库。那就是在建好的Cocos2d项目中直接搜索包含了iconv的文件名,找到文件iconv.h直接包含到项目中去,如:

#include "Cocos2d\external\win32-specific\icon\include\iconv.h"

然后就可以在项目中创建一个GBKToUTF8方法来实现编码的转换了,如范例3-3所示:

【范例3-3】使用iconv库显示中文。

01 //GBKToUTF8方法的实现
02      int HelloWorld::GBKToUTF8(std::string &gbkStr, const char* toCode, 
        const char* formCode)
03      {
04              iconv_t iconvH;
05              iconvH = iconv_open(formCode, toCode);
06              if (iconvH == 0){
07                      return -1;
08              }
09              const char* strChar = gbkStr.c_str();
10              const char** pin = &strChar;
11              size_t strLength = gbkStr.length();
12              char* outbuf = (char*)malloc(strLength * 4);
13              char* pBuff = outbuf;
14              memset(outbuf, 0, strLength * 4);
15              size_t outLength = strLength * 4;
16              if (-1 == iconv(iconvH, pin, &strLength, &outbuf, &outLength)){
17                      iconv_close(iconvH);
18                      return -1;
19              }
20              gbkStr = pBuff;
21              iconv_close(iconvH);
22              return 0;
23      }
24      //在场景中加入中文标签
25      std::string hello = "欢迎学习Cocos2d";
26      GBKToUTF8(hello, "gb2312", "utf-8");
27      CCLabelTTF* label1 = CCLabelTTF::create(hello.c_str(), "Arial", 20);
28      label1->setPosition(320,250);
29      this->addChild(label1);

具体的原理这里就不过多介绍了,原因主要有两点:第一是这种支持库只需要了解怎样使用就可以了,不需要额外花太多的精力去研究;其次是在实际开发中更加推荐第3种方法。

不过在安卓平台上Cocos2d并没有提供相应的库,这就需要开发者自行将iconv库引入到项目中,笔者已经将编译好的iconv库放在了源文件的本章目录下,可以在需要时自行下载。除了这两种以外,其实大家都一致推荐第3种方法,即读取XML文件用于显示中文内容。

(3)使用XML解析中文内容的方法非常简单,完整项目可以参考源文件目录下的ChapterThree02项目。我们要准备一个XML文件将其存放于目录Resources下,XML文件内容如范例3-4所示。

【范例3-4】用于在Cocos2d-x中显示中文的XML文件。

01 <dict>
02              <key>string1</key>
03           <string>欢迎学习Cocos2d-x</string>  
04          <key>string2</key>  
05          <string>使用XML显示中文</string>  
06          <key>str3</key>  
07          <string>key与string标签中的内容是对应的</string> 
08      </dict>

在XML文件中,<key>标签要与标签<string>保持一一对应的关系,这样就可以通过对key标签中的内容索引到对应的中文内容,从而达到显示中文的目的。之后要保存该文件,保存时要特别注意修改该文件的编码格式为utf-8,可以使用EditPlus来完成这一任务,如图3-3所示。

提示:实际上也可以通过对Cocos2d-x中的cpp文件的编码格式进行修改来达到直接显示中文的目的,但是非必要不推荐这样做。因为在修改代码的过程中还是要依赖于Visual Studio的,这样就需要修改许多次,非常不方便。

图3-3 修改XML文件的编码格式

接下来就可以在项目中加入从XML文件中读取文字内容的代码了,关键代码如范例3-5所示。

【范例3-5】将XML文件中的中文显示出来。

01 //创建词典类实例并将XML文件CHN_Strings.xml载入到词典中
02      auto *chnStrings = Dictionary::createWithContentsOfFile("CHN_Strings.xml");
03      //通过XML文件中的键(key)获取值(string)
04      const char *str1 = ((String*)chnStrings->objectForKey("string1"))-> getCString();
05      //创建标签将内容显示出来
06      auto* label1 = Label::create(str1, "Arial", 36);
07      label1->setPosition(320,270);                        //设置标签位置
08      addChild(label1);                                   //加入到场景中
09      const char *str2 = ((String*)chnStrings->objectForKey("string2"))-> getCString();
10      auto* label2 = Label::create(str2, "Arial", 36);
11      label2->setPosition(320, 180);       //设置标签位置
12      addChild(label2);                    //加入到场景中
13      const char *str3 = ((String*)chnStrings->objectForKey("string3"))-> getCString();
14      auto* label3 = Label::create(str3, "Arial", 36);        
15      label3->setPosition(320, 90);                        //设置标签位置
16      addChild(label3);                                   //加入到场景中

运行之后显示的内容如图3-4所示。不难看出中文已经可以正常地显示在屏幕中了,有兴趣的读者也可以尝试一下使用XML文件保存时的默认编码格式,即ASCII,看是否会出现乱码。

图3-4 利用XML在Cocos2d-x中显示中文内容

在Cocox2d-x中读取XML文件的方法非常简单,只需要创建一个词典类(Dictionary)就可以将XML文件中的内容读取出来,如范例3-5中第02行所示,其中createWithContentsOfFile方法的参数就是保存中文内容的XML文件名,之后就可以通过类似第04行所示的方法将中文内容读取出来了。其中objectForKey方法的参数就是在XML文件中<key>标签中存放的内容,词典对象会通过这个内容来找到与之对应的字符串,并保存到相应的字符变量中。再接下来就可以像英文字符串一样来使用它了。

使用XML文件还有一个说不上好处的好处,那就是可以支持多国语言,这主要是指一些可以同时支持中文、英文或者一些其他语言的游戏而言的,当然也包括了繁体中文。可以在游戏中设置一个选择语言的选项,然后根据选项来决定读取哪一个XML文件,这样就能够快速便捷地对游戏语言进行切换了。除此之外,在一些RPG游戏中,为了保存NPC的对话,也为了方便对这些对话进行管理,通常也会使用XML文件或者是类似的方法。