cocos2dx 4.0 3.x 标签 (Label) 中使用中文的方法与一些思考 (使用rapidjson)
本文是基于cocos2dx 4.0环境 理论上旧版也能使用
0 前言
在cocos2dx中,如需要在 Label 读取中文,直接写进参数里面是不行的,直接不显示。但是官方文档却说
A TTFConfig can also be used for displaying Chinese, Japanese and Korean characters.
TTFConfig 也能用于展示中文,日文,韩文的字符。
网上搜索出来的做法大多都是使用 Dictionary
类的方法读取一个XML文件,这个方法在4.0之前也一直挺好用,直到我升级到4.0之后发现这个类找不到了。粗略的翻了一下,发现我之前用的3.17版本中,这个类已经在 deprecated
也就是弃用文件夹中了,看了下官方的手册,也没有说道如何读取,那就需要另辟蹊径了。
1 一些思考
本小节都是基于我个人的经验和猜测,可能有非常不严谨的地方,如果想看解决方法,直接看下一小节
通过搜索,在这篇文章中提到了将文件保存为utf8格式可以缓解,但是治标不治本,对字符的个数有限制,不然直接不能编译。此时我先想到了用visual code打开visual studio生成的文件,都需要把编码换成gbk。然后我又想到了以前开发qt程序在qt中使用vs
编译器和mingw
编译器时也有这类毛病。那么我就猜测,createWithTTF
是可以使用中文的,只是万恶的编码问题导致c文件中的中文无法被正确编译。我还设想,如果不用visual studio进行开发,而是qt clion之类的,并且不使用vs编译器,会不会就能直接在参数给中文了呢?留给大家尝试了。
总结下来,createWithTTF
是可以使用中文的,只是编码问题导致vs的cpp文件中不能使用,那么只需要用任何一种方式读取出字符串便可以了。
2 通过rapidjson
通过搜索,我发现cocos2dx的 external
文件夹中,官方为用户准备了很多非常实用的第三方库,其中就有可以用来读取json的rapidjson
,网上一搜,发现在cocos中也有不少人在用,只不过好像没有提及用来读取中文标签。通过第一小节的猜测,我们可以借助它来实现中文标签。其原理就是读取json
文件中的中文字符串。
当然,里面貌似也有解析xml的库,或者你想塞个库解析ini都是可以的,我使用rapidjson
是感觉他很方便,而且如有用到,还能用于与服务器后端通信。
2-1 开始操作
我这里之作读取的用法,关于写入,请直接在网上搜索rapidjson
,他是c语言的库,不限于cocos,任何地方都可以使用。
- 我们准备一个json文件 例如这样
{
"key": "value",
"array": [
"1",
"2"
],
"HelloWorld": {
"loading": "资源读取中...",
"chinese": "中文字符串",
"auth": "Curry"
}
}
- 引入两个头文件
#include "json/rapidjson.h"
#include "json/document.h"
3.x版本没试过,如果不行试试在路径前面加上external/
- 通过cocos读取出文件的所有字符串 然后转换为rapidjson对象
rapidjson::Document JSON::mJsonObj;
//读取出所有字符串
std::string jsonStr = FileUtils::getInstance()->getStringFromFile("json/cn.json");
mJsonObj.Parse<rapidjson::kParseDefaultFlags>(jsonStr.c_str());
if (mJsonObj.HasParseError())
//出错处理
//读值
if (mJsonObj.HasMember("键名"))
{
//别的数据类型 int float 也是通过get***来读取
std::string str = mJsonObj["键名"].GetString();
}
//读对象
if (mJsonObj.HasMember("对象键名"))
if (mJsonObj["对象名"].IsObject())
{
rapidjson::Value subObject = mJsonObj["对象名"];
//然后再从subObject中读取值即可
}
//读数组
if (mJsonObj.HasMember("数组键名") && mJsonObj["数组键名"].IsArray())
{
rapidjson::Value arr = mJsonObj["数组键名"];
for (int i = 0; i < arr.Size(); ++i)
{
rapidjson::Value tmpObj = arr[i];
//然后再从tmpObj中读取值即可
}
}
- 这样就完成了json的读取
GetString
直接返回了const char*
放到label
里就可以了
auto lblTitle = Label::createWithTTF(mJsonObj["键名"].GetString(), "fonts/normal.ttf", 60);
lblTitle->setTextColor(Color4B::BLACK);
lblTitle->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.x + visibleSize.height / 2 - 150));
addChild(lblTitle, 1);
3 坑
我把这些写成了一个helper类,切换场景时直接通过同一个rapidjson::Document
进行处理,发现只要取到了二级对象/数组之后最初的rapidjson::Document
已经被改变,应该是指针的问题,可他没有深拷贝操作。所以,当你切换场景时,需要重新Parse
一次!