Cocos2d-x顯示中文與字幕滾動--之遊戲開發《趙雲要格鬥》(14),cocos2d捲軸
這裡是林炳文Evankaka的部落格,歡迎大家前來討論與交流~~~~~~
轉載請註明出處http://blog.csdn.net/evankaka
本文將要解決Cocos2d-x中顯示中文時出現亂碼的情形,並且實現一個字幕滾動的功能,這個功能是通過遮罩來實現的。
cocos2d-x版本:2.2.5
工程環境:windows7+VS2010
開啟檔案:將工程放在cocos2d-x安裝目錄下的project檔案夾下用VS開啟
先來看看效果:
在windows環境下使用visual studio開發cocos2d-x,由於visual studio 預設編碼為GBK格式,而cocos2d-x引擎預設編碼為UTF-8,如果有用到中文,在遊戲運行時有可能會出現亂碼的情況,這個問題一般有三種解決方案,如下
(1)將源碼檔案儲存為utf-8格式(不建議,治標不治本)
(2)自己編寫編碼轉碼,在用到中文的地方手動轉換
(3)將顯示文本單獨儲存為文字檔(該檔案編碼為utf-8),由系統統一模組管理文本讀取顯示,建議使用這種方式,便於後期系統維護,並實現國際化。(這裡沒寫了)
第一種方式很簡單就不不介紹了,下面將對第2種進行介紹。第3種還沒寫好。
一、自己編寫編碼轉碼,在用到中文的地方手動轉換。
cocos2d-x的開發包內建了用於編碼轉換的iconv庫,標頭檔"iconv.h"。iconv命令可以將一種已知的字元集檔案轉換成另一種已知的字元集檔案。它的作用是在多種國際編碼格式之間進行文本內碼的轉換。
1、 直接把代碼寫進要用到的地方
如果是只能到一次的話,推薦可以這麼做。
(1)首先,建立一個工程,然後在HelloWorldScene.cpp中添加標頭檔#include"iconv/iconv.h"/,
(2)然後在HelloWorldScene.cpp添加全域函數(記得要把它們放在所有函數的最上頭,要不就是最上頭再定義函數一下)
bool IConvConvert(const char *from_charset, const char *to_charset, const char *inbuf, int inlen, char *outbuf, int outlen){iconv_t cd = iconv_open(to_charset, from_charset);if (cd == 0) return false;const char **pin = &inbuf;char **pout = &outbuf;memset(outbuf,0,outlen);size_t ret = iconv(cd,pin,(size_t *)&inlen,pout,(size_t *)&outlen);iconv_close(cd);return ret == (size_t)(-1) ? false : true;}std::string IConvConvert_GBKToUTF8(const std::string& str){const char* textIn = str.c_str();char textOut[256];bool ret = IConvConvert("gb2312", "utf-8", textIn, strlen(textIn),textOut, 256);return ret ? std::string(textOut) : std::string();}
運行之後報錯:
error LNK2019:無法解析的外部符號 _libiconv_close
error LNK2019:無法解析的外部符號 _libiconv
error LNK2019:無法解析的外部符號 _libiconv_open
fatal error LNK1120: 3個無法解析的外部命令
解決方案:因為你沒有加libiconv.lib檔案
在工程屬性 ->配置屬性 ->連結器->輸入->附加依賴項添加libiconv.lib
如下:
(3)用法:
在用到的地方,我這裡是在init()裡添加
std::string str =IConvConvert_GBKToUTF8("我是林炳文Evankaka~~\n歡迎來到我的世界~~~");CCLabelTTF* pLabel = CCLabelTTF::create(str.c_str(), "Arial", 24);pLabel->setPosition(ccp(origin.x + visibleSize.width/2,origin.y + visibleSize.height - pLabel->getContentSize().height));this->addChild(pLabel, 1);
(4)效果:
2、單獨一個文字轉換檔
單獨儲存為 .h標頭檔,在使用到編碼轉換的cpp檔案include即可。如果要經常用到的話,建議用這種方法
記得在工程屬性 ->配置屬性 ->連結器->輸入->附加依賴項添加libiconv.lib
(1)在class檔案夾下建立一個名為ChineseString.h的檔案,並把它加到工程來。
#ifndef __ChineseString_H__ #define __ChineseString_H__ #include "iconv/iconv.h"//重點記得加上去static char g_GBKConvUTF8Buf[5000] = {0};class ChineseString{public:static const char* GBKToUTF8(const char *strChar)//將字串轉成UFT-8iconv_t iconvH;iconvH = iconv_open("utf-8","gb2312");if (iconvH == 0){return NULL;}size_t strLength = strlen(strChar);size_t outLength = strLength*4;size_t copyLength = outLength;memset(g_GBKConvUTF8Buf, 0, 5000);char* outbuf = (char*) malloc(outLength);char* pBuff = outbuf;memset(outbuf, 0, outLength);if (-1 == iconv(iconvH, &strChar, &strLength, &outbuf, &outLength)){iconv_close(iconvH);return NULL;}memcpy(g_GBKConvUTF8Buf,pBuff,copyLength);free(pBuff);iconv_close(iconvH);return g_GBKConvUTF8Buf;}};#endif (2)使用方法:
在要用到的地方先添加標頭檔ChineseString.h(記得加!)
然後是
CCLabelTTF* pLabel=CCLabelTTF::create(ChineseString::GBKToUTF8("<span style="font-family: Arial, Helvetica, sans-serif;">我是林炳文Evankaka~~\n歡迎來到我的世界~~~</span>"), "Arial", 24);<pre name="code" class="cpp"> pLabel->setPosition(ccp(origin.x + visibleSize.width/2,origin.y + visibleSize.height - pLabel->getContentSize().height));this->addChild(pLabel, 1);
(3)效果
二、字幕滾動
字幕滾動應該是要在一個範圍內可見的,出了這個範圍就不可見了,這裡實現其實很簡單,就是通過CCClippingNode來實現的.CCClipingNode是一個可裁剪節點,簡單理解:
(1)首先它是一個節點,繼承於CCNode,所以它可以像普通節點一樣放入CCLayer,CCScene,CCNode中。
(2)作為節點,它就可以用作容器,承載其他節點和精靈。我把它叫底板。
(3)如果想要對一個節點進行裁剪,那需要給出裁剪的部分,這個裁剪地區,我把它叫模版。
所以CCClipingNode裁剪節點在組成上=底板+模版,而在顯示上=底板-模版。不知道這樣解釋會不會好理解一點。
這裡直接建了一個類,將上面建立的中文轉換標頭檔 用了進來,這是標頭檔 GameString.h
#ifndef __GameString_SCENE_H__#define __GameString_SCENE_H__#include "cocos2d.h"#include "cocos-ext.h"#include "ChineseString.h"#include "HelloWorldScene.h"//這是遊戲介面的標頭檔USING_NS_CC;USING_NS_CC_EXT;class GameString : public cocos2d::CCLayer{public: virtual bool init(); static cocos2d::CCScene* scene(); CREATE_FUNC(GameString);//字幕滾動完成後調用void RollEnd();//跳過按鈕的事件void menuCloseCallback(CCObject* pSender);};#endif // __GameString_SCENE_H__
這是實現檔案 GameString.cpp
#include "GameString.h"CCScene* GameString::scene(){ CCScene *scene = CCScene::create(); GameString *layer = GameString::create(); scene->addChild(layer); return scene;}bool GameString::init(){ if ( !CCLayer::init() ) { return false; } CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize(); CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();//加個按鈕CCMenuItemImage *pCloseItem = CCMenuItemImage::create("exct.png","exct.png",this,menu_selector(GameString::menuCloseCallback));pCloseItem->setPosition(ccp( visibleSize.width -80 ,visibleSize.height-60));CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);pMenu->setPosition(CCPointZero);this->addChild(pMenu, 1); //加背景 CCSprite* pSprite = CCSprite::create("enter.png"); pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y)); this->addChild(pSprite, 0);//建立要顯示的文字CCLabelTTF* pLabel=CCLabelTTF::create(ChineseString::GBKToUTF8("我是林炳文Evankaka~~\n這是遊戲《趙雲要格鬥》\n歡迎來到我的世界~~~\n我是林炳文Evankaka~~\n這是遊戲《趙雲要格鬥》\n歡迎來到我的世界~~~\n我是林炳文Evankaka~~\n這是遊戲《趙雲要格鬥》"),"Arial",25);pLabel->setAnchorPoint(CCPointZero);ccColor3B color = ccc3(255,255,0);pLabel->setColor(color);pLabel->setPosition(ccp(50, -200));//Y軸注意為負,X軸對應下面的point[4]的50,讓他們對齊//繪製裁剪地區CCDrawNode* shap = CCDrawNode::create();CCPoint point[4] = {ccp(50,0), ccp(400,0), ccp(400,200), ccp(50,200)};//可以根據文字適當修改下大小shap->drawPolygon(point,4,ccc4f(255,255,255,255),0, ccc4f(255,255,255,255));//繪製四邊形////建立遮罩CCClippingNode* pClip = CCClippingNode::create();pClip->setInverted(false);pClip->setStencil(shap);//一定要有,要不會報錯pClip->addChild(pLabel);this->addChild(pClip);//開始讓字幕滾動啦CCMoveBy* moveact=CCMoveBy::create(10.0f,CCPointMake(0,400));//10秒向上移動400CCCallFunc* callFunc=CCCallFunc::create(this,callfunc_selector(GameString::RollEnd));//建立回調動作,文字飄動完後CCActionInterval* act=CCSequence::create(moveact,callFunc,NULL);//建立連續動作pLabel->runAction(act); return true;}void GameString::RollEnd(){CCDirector::sharedDirector()->replaceScene(HelloWorld::scene());//進入遊戲主介面}void GameString::menuCloseCallback(CCObject* pSender){RollEnd();//點擊跳過直接進入遊戲主介面}
效果:
(1)字幕滾動完成後進入遊戲主介面
(2)點擊跳過直接進入遊戲主介面