前言:
一个场景(Scene)是由多个层(Layer)组成,而且层的个数要至少是1,不能为0。
场景切换
场景切换相关函数
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