這篇文章是分析第一個小實例ActionTest的源碼。其實全部實例程序的結構都是同樣的,只有特定方法裏的代碼不一樣,大的框架都是同樣的。也就是說看完這篇文章你就能夠本身開始分析其餘源碼了。數組
廢話很少說,我們接着上一篇文章開始講。上一篇文章最後咱們講到開啓下個場景的代碼框架
void TestController::menuCallback(CCObject * pSender) { // 獲取被點擊的子菜單項, CCMenuItem* pMenuItem = (CCMenuItem *)(pSender); //獲取子菜單項的Zorder值,這個值就是在Z軸上的一個值,經過設置他能夠影響遮擋關係 //這裏呢,子菜單之間是沒有遮擋關係的,這個值其實就是用來獲取這個子菜單對應場景的index值 int nIdx = pMenuItem->getZOrder() - 10000; // 經過靜態方法CreateTestScene得到相應的場景並開始場景 TestScene* pScene = CreateTestScene(nIdx); if (pScene) { pScene->runThisTest(); pScene->release(); } }
pScene就是咱們要啓動的下一個場景,這裏你或許會注意到,這個pScene的類型不是CCScene,而是一個咱們不認識的類名。咱們找到定義TestScene地方,在testBase.h裏面函數
#ifndef _TEST_BASIC_H_ #define _TEST_BASIC_H_ #include "cocos2d.h" #include "VisibleRect.h" USING_NS_CC; using namespace std; class TestScene : public CCScene { public: TestScene(bool bPortrait = false); virtual void onEnter(); virtual void runThisTest() = 0; // The CallBack for back to the main menu scene virtual void MainMenuCallback(CCObject* pSender); }; typedef CCLayer* (*NEWTESTFUNC)(); #define TESTLAYER_CREATE_FUNC(className) \ static CCLayer* create##className() \ { return new className(); } #define CF(className) create##className #endif
咱們能夠看到類TestScene是繼承CCScene,這就沒問題了,他是個CCScene咱們是可使用它的。這個類裏面定義了構造函數和三個虛構函數。所謂虛構函數咱們能夠簡單的理解成是JAVA裏面的抽象函數,就是說在他的子類必需要實現這三個虛構函數。若是你想對virtual這個關鍵字有更多瞭解你能夠參考這裏:C++ Virtual詳解this
接下來的typedef CCLayer* (*NEWTESTFUNC)(); 這個地方NEWTESTFUNC是一個函數指針,該函數的參數爲空,返回值爲CCLayer的指針。參考:[C++語法] 關鍵字typedef用法(轉)。spa
再往下.net
#define TESTLAYER_CREATE_FUNC(className) \ static CCLayer* create##className() \ { return new className(); }
這個地方你能夠理解成簡單的替換。沒當出現TESTLAYER_CREATE_FUNC(className),他就會自動的替換爲後面的代碼。指針
最後一句咱們也能夠這樣簡單的理解。code
看完了TestScene的定義,讓咱們來看看他的實現。blog
#include "testBasic.h" #include "controller.h" //構造方法,調用父類的init()方法 TestScene::TestScene(bool bPortrait) { CCScene::init(); } //重寫父類的onEnter方法,想場景裏添加返回主菜單的MainMenu按鈕 void TestScene::onEnter() { CCScene::onEnter(); //add the menu item for back to main menu //#if (CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE) // CCLabelBMFont* label = CCLabelBMFont::create("MainMenu", "fonts/arial16.fnt"); //#else CCLabelTTF* label = CCLabelTTF::create("MainMenu", "Arial", 20); //#endif CCMenuItemLabel* pMenuItem = CCMenuItemLabel::create(label, this, menu_selector(TestScene::MainMenuCallback)); CCMenu* pMenu =CCMenu::create(pMenuItem, NULL); pMenu->setPosition( CCPointZero ); pMenuItem->setPosition( ccp( VisibleRect::right().x - 50, VisibleRect::bottom().y + 25) ); addChild(pMenu, 1); } //按鈕被按下的回調函數,(做用:返回主菜單) void TestScene::MainMenuCallback(CCObject* pSender) { CCScene* pScene = CCScene::create(); CCLayer* pLayer = new TestController(); pLayer->autorelease(); pScene->addChild(pLayer); CCDirector::sharedDirector()->replaceScene(pScene); }
代碼很簡單,主要是實現返回主菜單的功能。繼承
全部的小實例場景都會繼承這個TestScene,這樣咱們就不用在每一個小實例場景裏添加這個返回主菜單按鈕了。
讓咱們在回頭上面ActionTest這個小實例。當咱們點擊主菜單裏的ActionTest選項時, CreateTestScene(nIdx)方法會返回一個ActionsTestScene的實例,而後調用這個實例的runThisTest()方法,下面咱們來看一下這個方法。
void ActionsTestScene::runThisTest() { sceneIdx = -1; addChild(nextAction()); CCDirector::sharedDirector()->replaceScene(this); }
這個方法代碼不多,首先初始化sceneIdx爲-1,而後調用nextAction()函數,這個函數會返回一個CCLayer (層),而後把這個層加到場景中,最後開始場景。
咱們再看一下nextAction()這個函數。
static CCLayer* nextAction() { sceneIdx++; sceneIdx = sceneIdx % MAX_LAYER; //根據sceneIdx的值,獲取相應的CCLayer CCLayer* pLayer = (createFunctions[sceneIdx])(); pLayer->init(); pLayer->autorelease(); return pLayer; }
這個函數主要是把層的索引加一,而後根據索引得到相應的層並初始化,設置自動釋放。這裏面createFunctions是個函數指針數組,根據索引返回相應的函數指針。這裏面有個頗有意思的地方(我也不知道我理解的是否正確,若是錯誤請指正)。
typedef CCLayer* (*NEWTESTFUNC)();
NEWTESTFUNC定義如上 [C++語法] 關鍵字typedef用法(轉)
在他裏面咱們能夠看到,每一項都是形如CF(Name)的代碼。在編譯的時候這個會被替換爲reateName。這個是使用的define關鍵字
#define CF(className) create##className
無論怎麼說,這個就是爲了快速方便的獲取所要的層。
咱們從runThisTest函數開始看一下:在這裏初始化索引爲-1,而後調用nextAction函數,在nextAction函數裏,先把索引加一(這個時候索引就變成0了),在函數指針數組裏找到相應的函數指針(索引爲0時的函數指針指向的是ActionManual,從下方數組可查到)。
static NEWTESTFUNC createFunctions[] = { CF(ActionManual), CF(ActionMove), //省略部分代碼 CF(Issue1327), CF(Issue1398) };
根據CF的定義,咱們得到的函數指針是createActionManual。咱們要執行這個createActionManual方法了,你可能會納悶。在ActionStest.cpp裏面沒有這個函數啊。這裏呢我得看另一個define(直接理解爲後面的替代前面的東西就行)
#define TESTLAYER_CREATE_FUNC(className) \ static CCLayer* create##className() \ { return new className(); }
上面這段代碼是在ActionsTest.h裏定義的,你還能夠在ActionsTest.cpp裏看到他的使用
TESTLAYER_CREATE_FUNC(ActionManual); TESTLAYER_CREATE_FUNC(ActionMove); TESTLAYER_CREATE_FUNC(ActionRotate); //省略部分代碼 TESTLAYER_CREATE_FUNC(Issue1327); TESTLAYER_CREATE_FUNC(Issue1398);
在編譯的時候,ESTLAYER)CREATE_FUNC(ActionManual)就被替換爲了
static CCLayer* createActionManual() { return new ActionManual(); }
終於咱們找到這個函數了,這個函數只是簡單的建立了一個實例。他的onEnter方法會被自動調用。onEnter方法裏的代碼就是每一個小實例的不一樣了,其餘代碼都是同樣的。