cocos2d-x实战 C++卷 学习笔记--第6章 场景与层

前言:

一个场景(Scene)是由多个层(Layer)组成,而且层的个数要至少是1,不能为0。

cocos2d-x实战 C++卷 学习笔记--第6章 场景与层

场景切换

场景切换相关函数

1)void  runWithScene(Scene*  scene)

该函数可以运行场景。只能在启动第一个场景时调用该函数。如果已经有一个场景运行,则不能调用该函数。

2)void  replaceScene(Scene*  scene)

切换到下一个场景。用一个新的场景替换当前场景,当前场景被终端释放

3)void  pushScene(Scene*  scene)

切换到下一个场景。将当前场景挂起放入到场景堆栈中,然后再切换到下一个场景中。

4)void  popScene(Scene*  scene)

与 pushScene 配合使用,可以回到上一个场景。

5)void  popToRootScene(Scene*  scene)

与 pushScene 配合使用,可以回到根场景。

代码示例:

 #ifndef __HELLOWORLD_SCENE_H__
 #define __HELLOWORLD_SCENE_H__

 #include "cocos2d.h"
 #include "Setting.h"

 class HelloWorld : public cocos2d::Layer
 {
 public:
     // there's no 'id' in cpp, so we recommend returning the class instance pointer
     static cocos2d::Scene* createScene();

     // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
     virtual bool init();  

     // a selector callback
     void menuCloseCallback(cocos2d::Ref* pSender);

     ////
     void menuItemStartCallback(Ref* pSender);
     void menuItemSettingCallback(Ref* pSender);
     void menuItemHelpCallback(Ref* pSender);

     // implement the "static create()" method manually
     CREATE_FUNC(HelloWorld);
 };

 #endif // __HELLOWORLD_SCENE_H__
 #include "HelloWorldScene.h"

 USING_NS_CC;

 Scene* HelloWorld::createScene()
 {
     // 'scene' is an autorelease object
     auto scene = Scene::create();

     // 'layer' is an autorelease object
     auto layer = HelloWorld::create();

     // add layer as a child to scene
     scene->addChild(layer);

     // return the scene
     return scene;
 }

 // on "init" you need to initialize your instance
 bool HelloWorld::init()
 {
     //////////////////////////////
     // 1. super init first
     if ( !Layer::init() )
     {
         return false;
     }

     Size visibleSize = Director::getInstance()->getVisibleSize();
     Point origin = Director::getInstance()->getVisibleOrigin();

     /////////////////////////////
     // 2. add a menu item with "X" image, which is clicked to quit the program
     //    you may modify it.

     // add a "close" icon to exit the progress. it's an autorelease object
     auto closeItem = MenuItemImage::create(
                                            "CloseNormal.png",
                                            "CloseSelected.png",
                                            CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

     closeItem->setPosition(Point(origin.x + visibleSize.width - closeItem->getContentSize().width/ ,
                                 origin.y + closeItem->getContentSize().height/));

     // create menu, it's an autorelease object
     auto menu = Menu::create(closeItem, NULL);
     menu->setPosition(Point::ZERO);
     );

     /////////////////////////////
     // 3. add your codes below...

     // add a label shows "Hello World"
     // create and initialize a label

     auto label = LabelTTF::create();

     // position the label on the center of the screen
     label->setPosition(Point(origin.x + visibleSize.width/,
                             origin.y + visibleSize.height - label->getContentSize().height));

     // add the label as a child to this layer
     );

     // add "HelloWorld" splash screen"
     auto sprite = Sprite::create("HelloWorld.png");

     // position the sprite on the center of the screen
     sprite->setPosition(Point(visibleSize.width/ + origin.x, visibleSize.height/ + origin.y));

     // add the sprite as a child to this layer
     );

     ////// "开始" 精灵菜单
     Sprite* startSpriteNormal = Sprite::create("Demo1/start-up.png");
     Sprite* startSpriteSelected = Sprite::create("Demo1/start-down.png");
     MenuItemSprite* startMenuItem = MenuItemSprite::create(startSpriteNormal,
         startSpriteSelected,
         CC_CALLBACK_1(HelloWorld::menuItemStartCallback, this));
     startMenuItem->setPosition(Director::getInstance()->convertToGL(Point(, )));

     /// "设置" 图片菜单
     MenuItemImage* settingMenuItem = MenuItemImage::create(
         "Demo1/setting-up.png",
         "Demo1/setting-down.png",
         CC_CALLBACK_1(HelloWorld::menuItemSettingCallback, this));
     settingMenuItem->setPosition(Director::getInstance()->convertToGL(Point(, )));

     /// "帮助" 图片菜单
     MenuItemImage* helpMenuItem = MenuItemImage::create(
         "Demo1/help-up.png",
         "Demo1/help-down.png",
         CC_CALLBACK_1(HelloWorld::menuItemHelpCallback, this));
     helpMenuItem->setPosition(Director::getInstance()->convertToGL(Point(, )));

     Menu* mu = Menu::create(startMenuItem, settingMenuItem, helpMenuItem, NULL);
     mu->setPosition(Point::ZERO);
     this->addChild(mu);

     return true;
 }

 void HelloWorld::menuCloseCallback(Ref* pSender)
 {
 #if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
     MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
     return;
 #endif

     Director::getInstance()->end();

 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
     exit();
 #endif
 }

 void HelloWorld::menuItemStartCallback(Ref* pSender)
 {
     MenuItem* item = (MenuItem*)pSender;
     log("Touch Start %p", item);

     auto sc = Setting::createScene();
 //    Director::getInstance()->replaceScene(sc);
     Director::getInstance()->pushScene(sc);
 }

 void HelloWorld::menuItemSettingCallback(Ref* pSender)
 {
     MenuItem* item = (MenuItem*)pSender;
     log("Touch Setting %p", item);

 }

 void HelloWorld::menuItemHelpCallback(Ref* pSender)
 {
     MenuItem* item = (MenuItem*)pSender;
     log("Touch Help %p", item);

 }
 #ifndef __SETTING_SCENE_H__
 #define __SETTING_SCENE_H__

 #include "cocos2d.h"

 class Setting : public cocos2d::Layer
 {
 public:
     static cocos2d::Scene* createScene();
     virtual bool init();

     void menuSoundToggleCallback(cocos2d::Ref* pSender);
     void menuMusicToggleCallback(cocos2d::Ref* pSender);
     void menuOkCallback(cocos2d::Ref* pSender);

     CREATE_FUNC(Setting);
 };

 #endif   // __SETTING_SCENE_H__
 #include "Setting.h"

 // using namespace cocos2d;
 USING_NS_CC;

 Scene* Setting::createScene()
 {
     // 'scene' is an autorelease object
     auto scene = Scene::create();
     // 'layer' is an autorelease object
     auto layer = Setting::create();

     scene->addChild(layer);
     return scene;
 }

 bool Setting::init()
 {
     if (!Layer::init())
     {
         return false;
     }
     Size visibleSize = Director::getInstance()->getVisibleSize();
     Point origin = Director::getInstance()->getVisibleOrigin();

     Sprite*bg = Sprite::create("Demo1/setting-back.png");
     bg->setPosition(Point(origin.x + visibleSize.width / , origin.y + visibleSize.height / ));
     this->addChild(bg);

     // 音效
     auto soundOnMenuItem = MenuItemImage::create(
         "Demo1/on.png",
         "Demo1/on.png");
     auto soundOffmenuItem = MenuItemImage::create(
         "Demo1/off.png",
         "Demo1/off.png");
     auto soundToggleMenuItem = MenuItemToggle::createWithCallback(
         CC_CALLBACK_1(Setting::menuSoundToggleCallback, this),
         soundOnMenuItem,
         soundOffmenuItem,
         NULL);
     soundToggleMenuItem->setPosition(Director::getInstance()->convertToGL(Point(, )));

     // 音乐
     auto musicOnMenuItem = MenuItemImage::create(
         "Demo1/on.png",
         "Demo1/on.png");
     auto musicOffMenuItem = MenuItemImage::create(
         "Demo1/off.png",
         "Demo1/off.png");
     auto musicToggleItem = MenuItemToggle::createWithCallback(
         CC_CALLBACK_1(Setting::menuMusicToggleCallback, this),
         musicOnMenuItem,
         musicOffMenuItem,
         NULL);
     musicToggleItem->setPosition(Director::getInstance()->convertToGL(Point(, )));

     // OK 按钮
     auto okMenuItem = MenuItemImage::create(
         "Demo1/ok-down.png",
         "Demo1/ok-up.png",
         CC_CALLBACK_1(Setting::menuOkCallback, this));
     okMenuItem->setPosition(Director::getInstance()->convertToGL(Point(, )));

     Menu* mn = Menu::create(soundToggleMenuItem,
         musicToggleItem,
         okMenuItem,
         NULL);
     mn->setPosition(Point::ZERO);
     this->addChild(mn);

     return true;
 }

 void Setting::menuSoundToggleCallback(cocos2d::Ref* pSender)
 {
     MenuItem* item = (MenuItem*)pSender;
     log("Touch Setting::Music %p", item);
 }

 void Setting::menuMusicToggleCallback(cocos2d::Ref* pSender)
 {
     MenuItem* item = (MenuItem*)pSender;
     log("Touch Setting::Music %p", item);
 }

 void Setting::menuOkCallback(cocos2d::Ref* pSender)
 {
     MenuItem* item = (MenuItem*)pSender;
     log("Touch Setting::Ok %p", item);
     Director::getInstance()->popScene();
 }

关键代码解释:

1)使用 replaceScene

auto  sc = Setting::createScene();

Director->getInstance()->replaceScene(sc);

用 Setting 场景,替换当前的场景。当前场景被是否。

2)使用 pushScene

auto  sc = Setting::createScene();

Director->getInstance()->pushScene(sc);

将当前场景挂起放入到场景堆栈中,然后切换到 Setting 场景

3)使用 popScene

Director->getInstance()->popScene();

将当前场景释放,从 场景堆栈的栈顶 调入 一个 场景到程序中。(如果场景堆栈中没有场景,那么程序退出)

 场景过度动画:

场景切换时是可以添加过渡动画的,场景过渡动画是由 TransitionScene 类和它的子类展示的。

过渡动画类的使用方法如下:

 auto sc = Setting::createScene();
 auto reScene = TransitionFade::create(0.4f, sc);
 Director::getInstance()->pushScene(reScene);

第2行代码,创建 过渡动画 TransitionScene 对象,它的create函数有2个参数,第1个是动画持续时间,第2个是场景对象。

第3行代码中, pushScene 函数使用的参数是过渡动画 TransitionScene 对象,而不是场景对象。

场景的声明周期:

一般情况下一个场景只需要一个层。场景的生命周期可以通过层的生命周期反映出来,通过重写层的生命周期函数,可以处理场景不同生命周期阶段的事件。

例如,可以在层进入函数(onEnter)中做一些初始化处理,而在层退出函数(onExit)中释放一些资源。

层的声明周期函数如下:

    // 初始化层 调用
    virtual bool init();
    // 进入层时调用
    virtual void onEnter();
    // 进入层而且过渡动画结束时调用
    virtual void onEnterTransitionDidFinish();
    // 退出层时调用
    virtual void onExit();
    // 退出层而且开始过渡动画时调用
    virtual void onExitTransitionDidStart();
    // 层对象被清除时调用
    virtual void cleanup();

层(layer)继承于节点(node),这些生命周期函数根本上是从Node继承而来。

在重写层的生命周期函数中,第一行代码应该是调用父类的函数。如果不调用父类函数,会导致层中动画、动作或计划无法执行。

代码示例:

 // 进入层时调用
 void HelloWorld::onEnter()
 {
     Layer::onEnter();
     log("HelloWorld::onEnter()----- start ");
     log("HelloWorld::onEnter()----- end ");
 }

 void HelloWorld::onEnterTransitionDidFinish()
 {
     Layer::onEnterTransitionDidFinish();
     log("HelloWorld::onEnterTransitionDidFinish()----- start ");
     log("HelloWorld::onEnterTransitionDidFinish()----- end ");
 }

 // 退出层时调用
 void HelloWorld::onExit()
 {
     Layer::onExit();
     log("HelloWorld::onExit()----- start ");
     log("HelloWorld::onExit()----- end ");
 }

 // 退出层而且开始过渡动画时调用
 void HelloWorld::onExitTransitionDidStart()
 {
     Layer::onExitTransitionDidStart();
     log("HelloWorld::onExitTransitionDidStart()----- start ");
     log("HelloWorld::onExitTransitionDidStart()----- end ");
 }

 // 层对象被清除时调用
 void HelloWorld::cleanup()
 {
     Layer::cleanup();
     log("HelloWorld::cleanup()----- start ");
     log("HelloWorld::cleanup()----- end ");
 }

如果 HelloWorld 是第1个场景,当启动 HelloWorld 场景时,它的调用顺序是:

HelloWorld::init()-------- start
HelloWorld::init()-------- end
HelloWorld::onEnter()----- start
HelloWorld::onEnter()----- end
HelloWorld::onEnterTransitionDidFinish()----- start
HelloWorld::onEnterTransitionDidFinish()----- end

多场景切换生命周期:  

1)使用 pushScene 函数 实现从 HelloWorld 场景进入 Setting 场景  

Setting::init()------------- start
Setting::init()------------- end
HelloWorld::onExitTransitionDidStart()----- start
HelloWorld::onExitTransitionDidStart()----- end
Setting::onEnter()----- start
Setting::onEnter()----- end
HelloWorld::onExit()----- start
HelloWorld::onExit()----- end
Setting::onEnterTransitionDidFinish()----- start
Setting::onEnterTransitionDidFinish()----- end 

2)使用 replaceScene 函数实现从 HelloWorld 场景进入 Setting 场景

Setting::init()------------- start
Setting::init()------------- end
HelloWorld::onExitTransitionDidStart()----- start
HelloWorld::onExitTransitionDidStart()----- end
Setting::onEnter()----- start
Setting::onEnter()----- end
HelloWorld::onExit()----- start
HelloWorld::onExit()----- end
Setting::onEnterTransitionDidFinish()----- start
Setting::onEnterTransitionDidFinish()----- end
HelloWorld::cleanup()----- start
HelloWorld::cleanup()----- end 

3)使用 popScene 函数实现从 Setting 层场景切回到 HelloWorld 场景

Setting::onExitTransitionDidStart()----- start
Setting::onExitTransitionDidStart()----- end
Setting::onExit()----- start
Setting::onExit()----- end
Setting::cleanup()----- start
Setting::cleanup()----- end
HelloWorld::onEnter()----- start
HelloWorld::onEnter()----- end
HelloWorld::onEnterTransitionDidFinish()----- start
HelloWorld::onEnterTransitionDidFinish()----- end 
上一篇:Java8 Stream新特性详解及实战


下一篇:1001.A+B Format (20)解题描述