【Cocos2d-x游戲開發】解決Cocos2d-x中文亂碼的三種方法


  眾所周知,Cocos2d-x是一款不錯的開源引擎,但是在Cocos2d-x中直接使用中文是無法正確顯示的。比如下面的情況: 

                                                                  

  解決這個問題常用的有三種方法:1.通過轉換為UTF-8編碼來顯示。2.使用iconv庫來解決。3。使用解析xml或者json文件來解決。這里推薦使用第三種方法來解決,因為比較簡單方便,還能支持I18N國際化。下面我們來一一詳細了解一下每種解決方案的具體實現:

一、通過轉換為UTF-8編碼的方式顯示出來,建立一個方法用於轉換中文到對應的UTF-8編碼,具體代碼如下:

 1 char *HelloWorld::FontToUTF8(const char* font){
 2     int len = MultiByteToWideChar(CP_ACP,0,font,-1,NULL,0);
 3     wchar_t *wstr = new wchar_t[len+1];
 4     memset(wstr,0,len+1);
 5     MultiByteToWideChar(CP_ACP,0,font,-1,wstr,len);
 6     len = WideCharToMultiByte(CP_UTF8,0,wstr,-1,NULL,0,NULL,NULL);
 7     char *str = new char[len+1];
 8     memset(str,0,len+1);
 9     WideCharToMultiByte(CP_UTF8,0,wstr,-1,str,len,NULL,NULL);
10     if(wstr)delete[] wstr;
11     return str;
12 }

函數的使用方法如下:

1 auto label = Label::creat(HelloWorld::FontToUTF8("不如跳舞"),"Arial",36);
2 label->setPosition(320,300);
3 this->addChild(label);

這種方法僅僅依靠代碼實現而不不需要額外的設置,但是效果並不是很穩定,容易產生某些錯誤或者依然亂碼,因此不推薦該方法。

 

二、使用iconv庫來顯示中文

首先在創建好的cocos2d-x項目中搜索包含了iconv的文件名,然后把文件iconv.h的路徑引入,如:

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

然后在項目中創建一個GBKToUTF8方法來實現編碼的轉換:

 1 int HelloWorld::GBKToUTF8(std::string &gbkStr,const char* toCode,const char* formCode){
 2     iconv_t iconvH;
 3     iconvH = iconv_open(formCode,toCode);
 4     if(iconvH == 0){
 5         return -1;
 6     }
 7     const char* strChar = gbkStr.c_str();
 8     const char** pin = &strChar;
 9     size_t strLength = gbkStr.length();
10     char *outbuf = (char*) malloc(strLength*4);
11     char *pBuff = outbuf;
12     memset(outbuf,0,strLength*4);
13     size_t outLength = strLength*4;
14     if(-1 == iconv(iconvH,pin,&strLength,&outbuf,&outLength)){
15         iconv_close(iconvH);
16         return -1;
17     }
18     gbkStr = pBuff;
19     iconv_close(iconvH);
20     return 0;
21 }

函數的使用方法如下:

1 //在場景中加入中文標簽
2 std::string hello = "不如跳舞";
3 GBKToUTF8(hello,"gb2312","utf-8");
4 CCLabelTTF *label1 = CCLabelTTF::create(hello.c_str(),"Arial",20);
5 label->setPosition(320,250);
6 this->addChild(label);

不過Android平台上的Cocos2d-x並沒有提供相應的庫,這就需要開發者自行將iconv庫引入到項目中,然后編譯。

由於前兩種方法都比較復雜而且不穩定,因此推薦使用第三種方法(讀取xml文件或者json文件的方法顯示中文)。

 

三、讀取外部xml或者Json文件顯示中文

  1.xml方法

  使用xml解析中文十分的簡單,首先我們需要准備一個xml文件。如下所示: 

1 <dict>  
2     <key>string1</key>  
3     <string>歡迎學習cocos2dx</string>  
4     <key>string2</key>  
5     <string>使用XML顯示中文</string>  
6     <key>string3</key>  
7     <string>key與string標簽中的內容是對應的</string> 
8 </dict>  

  在xml文件中,<key>和<string>兩個標簽要保持一一對應的關系。這樣就可以通過對key標簽中的內容索引到對應的中文內容,從而顯示中文字符。

  需要注意的是保存此xml文件的時候編碼格式要使用UTF-8(可以使用notepad++或者sublimeText之類的軟件完成)。

  之后我們就可以解析xml文件來讀取中文啦:

 1     //創建詞典類實例,將xml文件加載到詞典中
 2     auto *chnStrings = Dictionary::createWithContentsOfFile("CHN_Strings.xml");
 3     //通過xml文件中的key獲取value
 4     const char *str1 = ((String*)chnStrings->objectForKey("string1"))->getCString();
 5     //創建一個標簽顯示出來
 6     auto* label1 = Label::create(str1, "Arial", 36);
 7     label1->setPosition(320,270);
 8     addChild(label1);
 9 
10     const char *str2 = ((String*)chnStrings->objectForKey("string2"))->getCString();
11     auto* label2 = Label::create(str2, "Arial", 36);
12     label2->setPosition(320, 180);
13     addChild(label2);
14 
15     const char *str3 = ((String*)chnStrings->objectForKey("string3"))->getCString();
16     auto* label3 = Label::create(str3, "Arial", 36);
17     label3->setPosition(320, 90);
18     addChild(label3);

  這樣中文就可以正確的顯示出來了。

  

 

  2.Json方法

   Json的方法和xml大同小異,而且更簡單,首先我們同樣准備一個json文件,命名為language.json:

  

{
    "start":"開始游戲",
    "setting":"設置",
    "exitGame":"退出游戲",
    "info":"馬三小伙兒",
    "restart":"重新開始",
    "win":"游戲勝利",
    "returnMenu":"返回主菜單",
    "bgMusic":"背景音樂",
    "effectMusic":"音效音量"
}

  然后我們使用Jsoncpp庫來讀取json文件,jsoncpp可以到這里去下載:https://sourceforge.net/projects/jsoncpp/ 。解壓之后我們只需要保留其中的src\lib_json和

include\json下的文件,並將其放在項目的Classess\json目錄下。或者圖省事可以直接下載我這個配置好的json目錄 (提取碼:40bb)。最后把json庫導入到我們的cocos2d-x項目中。如圖:

  

  為了方便使用和修改我們這里創建一個ReadJson類,這個類里面只有一個靜態的std::string ReadJson::getString(std::string name)方法,用來讀取json信息:

 1 std::string ReadJson::getString(std::string name){
 2     Json::Reader reader;
 3     Json::Value root;
 4 
 5     std::string data = FileUtils::getInstance()->getStringFromFile("language.json");
 6 
 7     if (reader.parse(data, root, false) == true)
 8     {
 9         return root[name].asCString();
10     }
11 }

  一步步解釋一下函數中的內容:

  Json::Reader 這個類是用來解析json文件的;

  Json::Value   這個類代表了json的一段數據;

  FileUtils::getInstance()->getStringFromFile("language.json") 這個函數用來加載一個json文件,其返回值是一個字符串;

  調用reader(Json::Reader類型)的parse函數開始解析json文件,解析的結果會保存在root對象中(Json::Value類型),讀取它的值很簡單,就像普通的數組使用索引一樣,比如root["id"]。然后還可以根據值的類型進行轉換,例如:root["name"].asCString();

  我們直接在程序中直接調用這個類的靜態函數就可以方便的讀取json中的字段了。比如:

  

1 //開始游戲按鈕
2     auto start_button = Button::create("button.png");
3     start_button->setScale(2);
4 //調用ReadJson的getString()方法
5     start_button->setTitleText(ReadJson::getString("start"));
6     start_button->setTitleFontName("微軟雅黑");
7     start_button->setTitleFontSize(16);
8     start_button->setPosition(Vec2(visibleSize.width / 2, visibleSize.height*0.7));
9     this->addChild(start_button);

  這樣中文也可以正常的顯示出來了。

  

 

  總結上面的三種方法,無疑是第三種方法最方便和穩定了。而且使用解析xml或者json還有另外的優勢就可以很方便地支持國際化。在游戲中設置一個語言選擇按鈕,然后根據選項來決定加載哪個xml或者json文件,這樣可以很方便的快捷的切換游戲語言。

 

作者:馬三小伙兒
出處:http://www.cnblogs.com/msxh/p/5588775.html
請尊重別人的勞動成果,讓分享成為一種美德,歡迎轉載。另外,文章在表述和代碼方面如有不妥之處,歡迎批評指正。留下你的腳印,歡迎評論!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM