zoukankan      html  css  js  c++  java
  • [置顶] 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详解

    接下来的typedef CCLayer* (*NEWTESTFUNC)();  这个地方NEWTESTFUNC是一个函数指针,该函数的参数为空,返回值为CCLayer的指针。参考:[C++语法] 关键字typedef用法(转)

    再往下

    #define TESTLAYER_CREATE_FUNC(className) 
    static CCLayer* create##className() 
    { return new className(); }

    这个地方你可以理解成简单的替换。没当出现TESTLAYER_CREATE_FUNC(className),他就会自动的替换为后面的代码。

    最后一句我们也可以这样简单的理解。

    看完了TestScene的定义,让我们来看看他的实现。

    #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方法里的代码就是每个小实例的不同了,其他代码都是一样的。

  • 相关阅读:
    【Linux笔记】Linux目录结构
    《Effective C#》快速笔记(五)-
    《Effective C#》快速笔记(四)- 使用框架
    《Effective C#》快速笔记(三)- 使用 C# 表达设计
    《Effective C#》快速笔记(二)- .NET 资源托管
    《Effective C#》快速笔记(一)- C# 语言习惯
    Visual Studio 数据库架构比较
    C# 反射与dynamic最佳组合
    C# 调用WebApi
    基于微软开发平台构建和使用私有NuGet托管库
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3165589.html
Copyright © 2011-2022 走看看