• Cocos2d-x入门之旅[4]场景


    我们之前讲了场景图(Scene Graph) 的概念,继续之前你先要知道

    • 场景图决定了场景内节点对象的渲染顺序
    • 渲染时 z-order 值大的节点对象会后绘制,值小的节点对象先绘制

    HelloWorld

    你还记得HelloWorld场景是如何启动的么?回看我们工程里的AppDelegate.cpp,滚到applicationDidFinishLaunching()的尾部:

    // create a scene. it's an autorelease object
    auto helloWorldscene = HelloWorld::createScene();
    // run
    director->runWithScene(helloWorldscene);
    

    Ctrl+鼠标左键 点选createScene()查看定义,可以看到这个函数在HelloWorldScnen.h内声明,在HelloWorldScnen.cpp内定义

    // HelloWorldScnen.h
    static cocos2d::Scene* createScene();
    
    // HelloWorldScnen.cpp
    Scene* HelloWorld::createScene()
    {
        return HelloWorld::create();
    }
    

    我们可以通过该函数获取一个HelloWorld场景对象

    之后就是场景的初始化,菜单,精灵等对象的Set都在这里进行

    bool HelloWorld::init()
    {
        ...
    }
    

    最后我们看到一个回调函数

    void HelloWorld::menuCloseCallback(Ref* pSender)
    {
        //Close the cocos2d-x game scene and quit the application
        Director::getInstance()->end();
    }
    

    C++基础差的同学可能还不理解回调的概念,但你只需要知道,这个函数实现了:HelloWorld场景内点击关闭按可钮关闭窗口 的功能,就行了、

    SecondScene

    现在我们对着HelloWorld的代码来创建一个SecondScene

    和HelloWorld一样,首先我们需要一份SecondScene.h存放声明,然后是一份SecondScene.cpp存放定义

    注意VS内新建文件时,一定要保存到Class文件夹内,不然你是不能直接include“xxxxxx”的(万恶的VS默认保存路径不是Class

    修改到项目目录下的Class

    SecondScene.h

    首先是套一层宏保护到头尾

    #ifndef __SECOND_SCENE_H__
    #define __SECOND_SCENE_H__
    
    #endif // __SECOND_SCENE_H__
    

    然后

    #include "cocos2d.h"
    

    现在我开始我们要做一点点小变化,我们让SecondScene继承Layer而不是Scene

    class SecondScene : public cocos2d::Layer {
    public:
    	static cocos2d::Scene* createScene();
    	virtual bool init();
    	CREATE_FUNC(SecondScene);
        //暂时不需要回调函数
    };
    

    实际上之前的cocos实例工程里HelloWorld都是继承自Layer的,不知为何现在改了,但是无妨,我们借此机会介绍Layer和Scene的区别

    SecondScene.cpp

    首先要include我们之前写好的SecondScene.h,为了方便我们也和HelloWorld一样using namespace cocos2d

    你可能看到了HelloWorld.cpp里写的是USING_NS_CC而不是using namespace cocos2d,但其实效果是一样的

    接下来我们定义creatSceen()函数,也和HelloWorld::createScene()略有不同

    Scene* SecondScene::createScene() {
        //创建一个Scene类的对象scene
    	auto scene = Scene::create();
        //创建一个SecondScene类的对象layer
    	auto SecondScene = SecondScene::create();
        //把layer添加到scene里
    	scene->addChild(layer);
        //返回scene
    	return scene;
    }
    

    理解起来很简单:首先我们创建了一个Scene类的对象scene,然后创建了一个SecondScene类的对象layer(别忘了我们的SecondScene继承自layer),再把layer添加到了scene里,最后返回我们的scene

    之后就可以开始写初始化函数了

    bool SecondScene::init() {
    	auto visibleSize = Director::getInstance()->getVisibleSize();
    	Vec2 origin = Director::getInstance()->getVisibleOrigin();
    
    	Label* label = Label::create("Second Test", "fonts/Marker Felt.ttf", 24);
    	label->setPosition(
    		Vec2(
    			origin.x + visibleSize.width / 2,
    			origin.y + visibleSize.height - label->getContentSize().height
    		)
    	);
        
    	this->addChild(label);	// 默认z-order=0
    
    	return true;
    }
    
    

    我们不用加太多东西,加入一个label让自己知道这是SecondScene场景就行

    现在我们去程序的入口,AppDelegate.cpp里看看,还记得启动HelloWorld场景的那两行代码么,我们改成启动SecondScene场景:

    (记得先要加入#include "SecondScene.h"到AppDelegate.cpp里)

    // create a scene. it's an autorelease object
    auto helloWorldscene = HelloWorld::createScene();
    // run
    director->runWithScene(helloWorldscene);
    
    

    改成

    auto secondScene = SecondScene::createScene();
    director->runWithScene(secondScene);
    
    

    运行测试:

    没有问题

    场景切换

    接下来我们把AppDelegate.cpp还原回去(Crtl+Z),让程序运行时还是从HelloWorld场景开始,然后尝试使用回调函数切换到SecondScene

    由于我们要在HelloWorld切换到Second,所以我们需要在HelloWorld场景里添加一个回调事件,刚好HelloWolrd里就有一个关闭按钮的回调,我们改改代码就行(这里重点是演示如何切换,真的不是我懒)

    追踪到HelloWorld::menuCloseCallback()

    Director::getInstance()->END改成

    Director::getInstance()->replaceScene(
        SecondScene::createScene()
    );
    
    

    运行测试,不出意外再点击HelloWorld右下角的关闭按钮,就会一瞬间切换到Second

    切换动画

    Cocos内置了很多切换场景的动画,比如

    Director::getInstance()->replaceScene(
        TransitionSlideInT::create(
            3.0f, SecondScene::createScene()
        )
    );
    
    

    运行,Second会在3秒内从上平滑切换掉HelloWorld

    别的切换动画就不赘述了,和Actions又异曲同工之妙,各自己试试吧

    场景栈

    我们之前都是在使用replaceScene进行场景切换,replaceScene会使前一个场景被释放(简单来说就是删掉了,不再占用内存,想找回来只能重新创建一个),节省了内存资源,但有时我们不希望场景被释放怎么办呢

    Cocos还提供了 推进pushScene()和弹出popScene两种方法,把一系列场景存储到栈内,按需弹出(释放)和推进新场景

    是一种数据结构,你可以简单理解为一个弹匣,对栈有两种操作:

    1. 入栈(push),装入子弹
    2. 出栈(pop),射出子弹

    子弹总是最上面的先被射出(pop时栈顶的元素最先出栈),也就是“先进后出”

    新加入场景时使用pushScene(),新旧场景就会被存入场景栈,新在上旧在下(也就是说旧的场景没有释放),popScene会将新的场景释放,旧的场景就被弹了上来原来的位子,显示旧场景

    你可以在场景初始化函数内写一段等待x秒的代码(换个思路,可以写一个计时器),验证pop后显示的旧场景不是新创建的:

    bool HelloWorld::init()
    {
     	... 
            
        for(int i = 0; i <19999999; i++)// 耗时操作   
            
        ...
    }
    
    

    发挥你的奇思妙想,还有什么方法,自己实验一下

    层和场景

    这个好理解,想想你玩过的2d游戏,或者Photoshop的图层界面,一个场景里可以有好几个层

    场景内创建层很简单:

    Layer* layer2 = Layer::create();
    
    

    当然一个层必须添加到场景内才会生效,层无法离开场景独立存在

    之后的学习中我们会进一步体会到层的作用

  • 相关阅读:
    ABAP Help Document(2):1.2 表达式
    ABAP Help Document(1):1.1关键字
    api——》将.doc文件转成.docx文件后缀,且仅需要输入单个文件绝对路径
    python 更改默认输出 解决编码常出错问题
    爬取法律法规代码(可直接使用)
    python datetime 模块详解
    python 获得日期列表中最大日期(能够剔出不是日期类型)
    博客园页面css
    日期大小比较令解决{strftime('%Y年%m月%d日')}出错问题
    CodeForces
  • 原文地址:https://www.cnblogs.com/zhxmdefj/p/11727785.html
Copyright © 2020-2023  润新知