摘要: cocos2dx 是一款優秀的多平台,專為2D游戲設計的引擎. 在活躍的開源社區的推進下, 越發穩定和強大. 2.x -> 3.x的更新幅度很大, 性能的提升和功能的豐富也非常明顯. 但在享受進步的同時,也要承受遷徙之苦. 本文主要是總結自己遷徙的經歷, 以防大家走彎路.
- 博客: http://www.cnblogs.com/jhzhu
- 郵箱: jhzhuustc@gmail.com
- 作者: 知明所以
- 時間: 2014-06-22
基礎准備
- 我一直把VS當作主開發環境, eclipse和xcode作為特定機型的調試環境. 所以, 偷個懶, 假設你也在用VS開發. 另外兩個平台也也都有正則表達式替換功能, 大同小異.
- 在這里, 假設你已經搭好了3.x的VS開發環境, 能正常運行
HelloWorld演示. - 假設你有一定的正則表達式基礎. 如果沒有的話, 可參考這篇速成教程:正則表達式30分鍾入門教程
進入正題
cocos2dx 3.1的簡要feature更新介紹可參考這里, 詳細的changelog可參考這里.在升級之前, 建議掃一遍changelog( 否則都不知道要做啥…).
接下來, 進入正題啦:
語法更新
本文將有非常多字符串替換的步驟, 都在vs2012中進行. vs2012中字符串替換窗口如下:
本文將上圖代表的替換表示為:( 以后將不特殊說明 )
//regex-replace
\bUIImageView\b ==> ui::ImageView
obj-c式命名 ==> c++命名空間式命名
以下是常見的替換:
//regex-replace
//Widget:
\bUIWidget\b ==> ui::Widget
\bUIImageView\b ==> ui::ImageView
\bUIButton\b ==> ui::Button
...
\bUILayout\b ==> ui::Layout
\bUILabel\b ==> ui::Text
\bUILayer\b ==> Layer
\bCCObject\b ==> Ref
...
\baddTouchEventListener\s*\(\s*(.+)\s*,\s*toucheventselector\s*\((.*)\)\s*\) ==> addTouchEventListener( CC_CALLBACK_2( $2, $1 ))
\bTouchEventType\b ==> ui::Widget::TouchEventType
\bTOUCH_EVENT_([A-Z]+)\b ==> ui::Widget::TouchEventType::$1 \baddWidget\b\s*\( ==> addChild(
注釋: \b代表單詞的分割符. ()代表被標記的內容, $1 代表原始字符串中被標記的內容中的第一段. 具體請參考在 Visual Studio 中使用正則表達式.
include文件變更
因為包結構的變化, 所以有些組件的定義會未被include.
主要用到的head文件有:
| head | 描述 |
|---|---|
cocos2d.h |
cocos2dx的基本數據類和Node類都包含在里面 |
ui/CocosGUI.h |
cocos2dx 絕大部分的UI類都包含在內. 2.x版本中, UI類都包含在cocos-ext.h中. 所以絕大部分原來引用cocos-ext.h的地方都需要引用此文件 |
cocostudio/CocoStudio.h |
cocostudio功能相關的類都包含在里面. 最主要的是各種讀取json文件的Reader. 其次, 是Armature動畫. |
cocos-ext.h |
相比2.x的cocos-ext.h, 此文件做了非常大的精簡. 現在主要包括CCScrollView及其子類, 另外還有EditBox |
std::function作為監聽函數
雖然, 3.1 的版本仍然支持絕大多數老版本的回調函數方式, 比如: m_btnSubmit->addTouchEventListener (this,toucheventselector(RewardItemCell::onBtnSubmitClick));仍然能工作. 但是, 不能保證在將來的3.x版本中仍然如此. 所以, 盡量一次搞定吧. 在obj-c式命名 ==> c++命名空間式命名章節中, 有批量替換的正則表達式,可作為參考.
功能更新
中間層UILayer的去除
在2.x版本, Widget需要作為UILayer的孩子節點才能響應觸摸事件; 而在3.x版本中取消了這個限制, Widget的響應機制變為跟Menu類似. 目前, 我也沒有大量的去掉之前的UILayer層, 大部分功能仍然正常工作.
鍵盤響應方式變更
在2.x版本中, 鍵盤響應的監聽是用CCDirector::sharedDirector()->getKeypadDispatcher()->addDelegate(this);實現的. 在3.x版本中是這樣:
auto keyListener = EventListenerKeyboard::create();
keyListener->onKeyReleased = CC_CALLBACK_2(MainScene::keyBackClicked, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(keyListener, this);
監聽的取消, 也要做響應的替換.
Armature的陷阱
在2.x版本中, 一般通過下面的方式來監聽Armature的事件. 在監聽到COMPLETE的時候, 可以將此Armature移出場景.
CCArmature* swf = CCArmature::create(swfName);
swf->getAnimation()->setMovementEventCallFunc(this, movementEvent_selector(OutCardEffectHelper::onAnimationEnd));
但是在3.x中, 我們不能在監聽事件的回調函數中做任何可能會導致release此對象的操作. 否則, 會導野指針錯誤.
是不是有點雞肋? 我們來看看這種情況是怎么發生的:
我臨時用定時器來移除Armature的. 具體過程如下:
1. 為ArmatureAnimation增加一個公開函數: virtual MovementData *getMovementData() const { return _movementData; }
2. 通過下面的方式來移除: (PS: Lmada 表達式真是好用啊啊啊啊啊 )
auto data = swf->getAnimation()->getMovementData();
float speed = data->scale;
float frames = data->duration;
float delay = frames/60/speed;
string id = FORMAT_TEXT( "%p", swf );
Director::getInstance()->getScheduler()->schedule( [swf](float t){swf->removeFromParent();},this,0,0,delay,false, id);
更加優雅的anchorPoint
如果你加載了cocostudio生成的ui json文件, 並改動過內部Widget的位置的話, 你會發現, 代碼中x=20跟cocostudio ui編輯器中x=20效果是不一樣的.
問題出在哪里呢?
簡單來說, 2.x版本中的anchorPoint對自己在父親節點的位置和孩子節點在自己中的位置都有影響; 3.x版本中的anchorPoint只對自己在父親節點中的位置有影響.
舉個例子. 假設A是父親節點,B是A的孩子節點. A和B同為10*10的正方形.
A.anchorPoint = Point(0.5,0.5);
A.setSize(Size(10,10))
B.anchorPoint = Point(0.5,0.5);
B.setSize(Size(10,10))
B.setPosition( Point::ZERO );
A.addChild(B);
在2.x版本中: A和B的位置完全重合
在3.x版本中: B的中心點和A的左下角的點重合.

Sprite的默認GLProgram
什么?你沒聽過GLProgram, 那恭喜你, 可以跳過這小節了. 因為你肯定不會出現下面的惱人情況.
SHADER_NAME_POSITION_TEXTURE_COLOR是2.x版本中的默認GLProgram. 它對應的vect和frag分別是:ccPositionTextureColor_vert和ccPositionTextureColor_frag. vect用來確定位置,frag用來確定色彩.
然而, 在3.x版本中,默認的GLProgram是SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP, 對應的vect和frag分別是:ccPositionTextureColor_noMVP_vert和ccPositionTextureColor_noMVP_frag.
如果你恰好用過ccPositionTextureColor_vert的話, 建議改為ccPositionTextureColor_noMVP_vert. 否則會出現莫名的位置偏移問題.
stl::vector的不穩定排序導致的層級問題
2.x版本中, 如果沒有對孩子設置過zOrder的話, 孩子節點的覆蓋順序為: 后加的節點在上層, 先加的節點在下層.
3.x版本中, win32環境下, 孩子節點的覆蓋層級還能保續. 但是在android平台下, zOrder相同的孩子, 層級順序是隨機的. 關鍵在下面的代碼:
void Node::sortAllChildren()
{
if( _reorderChildDirty ) {
std::sort( std::begin(_children), std::end(_children), nodeComparisonLess );
_reorderChildDirty = false;
}
}
win32和android平台對stl::sort()的實現不同, android下的排序算法不是穩定的. 解決方法:
- 修改上述代碼, 實現穩定排序
- 添加孩子節點的時候手動設置
zOrder來保證層級順序.
umeng等第三方庫的更新
第三方庫, 也有很多跟cocos2dx版本相關. 注意升級, 否則會閃退.
Written with StackEdit.
