[置頂] Cocos2d-x 實例源碼分析之二 小實例的主框架

這篇文章是分析第一個小實例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方法裏的代碼就是每一個小實例的不一樣了,其餘代碼都是同樣的。

相關文章
相關標籤/搜索