这篇文章是分析第一个小实例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方法里的代码就是每一个小实例的不一样了,其余代码都是同样的。