cocos2d-x 四(游戏场景与场景切换)

首先是一些常识的介绍,这里有篇文章:http://article.ityran.com/archives/3283

简单的说来,一个游戏中包含的主要元素就是导演,场景,层,精灵,其实就是和拍戏一样,导演负责按“剧本”控制场景、层和精灵(演员),这“剧本”当然是我们自己设计的,比如:有什么角色演员,什么样的场景下演员可以或者应该做什么动作……而导演负责执行和控制这些元素将“剧本”以动态可视化的表现形式展现出来,最后看起来就像一部“电影”。

场景和层都可以看作是一个容器,场景可以用来包含层和精灵,而层可以用来包含精灵或者其它层。层是有层级的,就像photoshop中处理图象时用来独立控制某个或者某组元素显示效果所使用的层,层级越高,在场景中的显示权重就越高,就是拍戏中的主角一样,曝光率就越高。

场景切换在游戏中常用于关卡或者地点场景的切换,负责控制切换的理所当然地就是导演类CCDirector了,在cocos2d-x中包含了普通场景切换和带效果的场景切换两种方式,有人说带效果的场景切换就是对普通场景的一个包装,其实再说具体点,就是在一个场景被替换或者创建加载的时候用一个切换效果函数改变这个场景消失或者显示的动画过程(如渐变退出或者渐变显示),所以可以在源代码里看到有些是用了action作为场景过渡的动画效果。在CCDirector中常用的替换场景的方法有三个:

//终止正在运行的场景,把它放到暂停场景的堆栈(内存)中去,新的场景将被执行。由于将场景放置内存中,场景并没有release。
pushScene(CCScene *pScene);
//将经过pushScene的场景从堆栈(内存)中pop出来执行(前提是堆栈内存中存在场景),而当前执行的场景将被删除。
popScene(void);
//用一个新的场景去替换掉正在运行的场景,正在运行的场景将被终止。
replaceScene(CCScene *pScene);
这里需要注意的就是,在关于pushScene()的代码说明中写明了,应该尽量避免将一个大的场景压入堆栈中以减少内存的占用,所以常用的一般都是replaceScene(),当替换的场景没有使用切换效果时就是普通的场景切换,否则会按设定的效果进行场景的切换,cocos2d的场景切换效果有很多,这里就不多说了,可以直接进源代码里看。下面是场景切换的示例,在这里引用了testCPP中的一些数据,因为官方原例过于复杂,所以这里抽出主要的东西来说:

首先是需要两个场景,第一个场景其实在创建工程的时候就已经创建了,可以自行定义第二个场景和装有精灵的层,代码如下:

class TestLayer2 : public cocos2d::CCLayer
{
public:
    TestLayer2(void);
    ~TestLayer2(void);

    void restartCallback(CCObject* pSender);
    void nextCallback(CCObject* pSender);
    void backCallback(CCObject* pSender);

    void step(float dt);

    virtual void onEnter();
    virtual void onEnterTransitionDidFinish();
    virtual void onExitTransitionDidStart();
    virtual void onExit();
	 CREATE_FUNC(TestLayer2);
};

class TestScene : public cocos2d::CCScene
{
public: 
    TestScene(bool bPortrait = false);
    virtual void onEnter();

   // virtual void runThisTest() = 0;

    // The CallBack for back to the main menu scene
    virtual void pMainMenuCallback(CCObject* pSender);
};

当然,上面的代码都是从原例中拷过来修改成的,可以看到上面有过渡事件,可以根据需求在里面写代码,原例是加了个输出日志,然后下面是CPP代码的重写,用来添加精灵(控件图片什么的):

TestLayer2::TestLayer2()
{
    float x,y;

    CCSize size = CCDirector::sharedDirector()->getWinSize();
    x = size.width;
    y = size.height;

    //CCSprite* bg1 = CCSprite::create(s_back2);
    //bg1->setPosition( ccp(size.width/2, size.height/2) );
    //addChild(bg1, -1);

    //CCLabelTTF* title = CCLabelTTF::create((transitions[s_nSceneIdx]).c_str(), "Thonburi", 32 );
    //addChild(title);
    //title->setColor( ccc3(255,32,32) );
    //title->setPosition( ccp(x/2, y-100) );

    CCLabelTTF* label = CCLabelTTF::create("SCENE 2", "Marker Felt", 38);
    label->setColor( ccc3(16,16,255));
    label->setPosition( ccp(x/2,y/2));    
    addChild( label);

}

void TestLayer2::onEnter()
{
    cocos2d::CCLayer::onEnter();
    CCLog("Scene 2 onEnter");
}

void TestLayer2::onEnterTransitionDidFinish()
{
    CCLayer::onEnterTransitionDidFinish();
    CCLog("Scene 2: onEnterTransitionDidFinish");
}

void TestLayer2::onExitTransitionDidStart()
{
    CCLayer::onExitTransitionDidStart();
    CCLog("Scene 2: onExitTransitionDidStart");
}

void TestLayer2::onExit()
{
    CCLayer::onExit();
    CCLog("Scene 2 onExit");
}

TestScene::TestScene(bool bPortrait)
{
    
    CCScene::init();
}

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::pMainMenuCallback));

    CCMenu* pMenu =CCMenu::create(pMenuItem, NULL);
	 CCSize size = CCDirector::sharedDirector()->getWinSize();

    pMenu->setPosition( CCPointZero );
    pMenuItem->setPosition( ccp(size.width - 50, size.height-25) );

    addChild(pMenu,2);
}

void TestScene::pMainMenuCallback(CCObject* pSender)
{
	CCScene* s = HelloWorld::scene();
	CCScene* psScene = CCTransitionShrinkGrow::create(1, s);
	if (psScene)
    {
    CCDirector::sharedDirector()->replaceScene(psScene);
	}   
}

void HelloWorld::menuCloseCallback(CCObject* pSender)
{

    // "close" menu item clicked
	CCScene* s =new TestScene();

    CCLayer* pLayer = new TestLayer2();
    s->addChild(pLayer);

    //CCScene* psScene = CCTransitionShrinkGrow::create(1, s);


	CCScene* psScene =CCTransitionFade::create(1,s, ccc3(255,255,255));
    s->release();
    pLayer->release();
    if (psScene)
    {
        CCDirector::sharedDirector()->replaceScene(psScene);
    }   
    //CCDirector::sharedDirector()->end();
}
通过上面的代码,就能实现两个场景间的切换了,可以在这里下载到源代码,里面包含了这三次笔记的内容http://download.csdn.net/detail/cyistudio/5430853