我们之前讲了场景图(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();

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

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

Cocos2d-x入门之旅[4]场景的更多相关文章

  1. Cocos2d-x入门之旅[1]场景

    在游戏开发过程中,你可能需要一个主菜单,几个关卡和一个END的界面,如何组织管理这些东西呢? 和其他游戏引擎类似,Cocos也使用了场景(Scene) 这个概念 试想象一部电影或是番剧,你不难发现它是 ...

  2. Swift语言入门之旅

    Swift语言入门之旅  学习一门新的计算机语言,传统来说都是从编写一个在屏幕上打印"Hello world"的程序開始的.那在 Swift,我们使用一句话来实现它: printl ...

  3. cocos2d基础入门

    HelloCpp中Classes目录下放开发者自己的类: win32:平台相关,coco2d已默认创建:coco2d-x目录下,samples/cpp/HelloCpp/(工程根目录)图片放置位置:根 ...

  4. nginx入门系列之应用场景介绍

    目录 HTTP服务器 反向代理服务器 作为一个虚拟主机下多个应用的反向代理 作为多个虚拟主机的反向代理 负载均衡器 简单轮训策略 最小连接数策略 客户端IP哈希策略 服务器权重策略 邮件代理服务器 官 ...

  5. Cocos2d-x入门之旅[2]精灵

    精灵就是cocos是屏幕上移动的对象,能被我们控制,比如我们HelloWorld场景的这个图片就是精灵(Sprite) 怎么才算精灵?你能控制它的,就是一个精灵,否则就只是一个节点(Node) 准确的 ...

  6. Cocos2d-x入门之旅[3]动作

    Cocos通过动作(Action)可以让精灵动起来,把数个动作组成序列(Sequence)就能让精灵做出连续的动作,在动作中我们可以改变精灵的位置,旋转角度,缩放比例,等等 动作(Action) 首先 ...

  7. Cocos2d-x入门之旅

    Cocos通过动作(Action)让精灵动起来,把数个动作组成序列(Sequence)就能让精灵做出连续的动作,在动作中我们可以改变精灵的位置,旋转角度,缩放比例,等等 动作(Action)# 首先我 ...

  8. IOS-swift5.1快速入门之旅

    快速之旅 传统表明,新语言中的第一个程序应在屏幕上打印“Hello,world!”字样.在Swift中,这可以在一行中完成: print("Hello, world!") // P ...

  9. 云原生 - 体验Istio的完美入门之旅(一)

    作者:justmine 头条号:大数据达摩院 微信公众号:大数据处理系统 创作不易,在满足创作共用版权协议的基础上可以转载,但请以超链接形式注明出处. 为了方便大家阅读,可以关注头条号或微信公众号,后 ...

随机推荐

  1. 让你的AI模型尽可能的靠近数据源

    来源:Redislabs作者:Pieter Cailliau.LucaAntiga翻译:Kevin (公众号:中间件小哥) 简介 今天我们发布了一个 RedisAI 的预览版本,预集成了[tensor ...

  2. Java第三次作业第一题

    1.[请复制本程序,作为java程序代码,进行编译,补充填写缺失代码部分,并实现题目要求功能,从而获得空白填写所需的内容.] 编写无限计时程序,从0:1开始计时,一直循环计时,计时到60秒,变为1:0 ...

  3. 容器时代的持续交付工具---Drone:Drone介绍与安装

    Drone:Drone is a Container-Native, Continuous Delivery Platform. 官方给的定义,从上面的定义可以得出两个关键点: 1,Container ...

  4. adb命令整理(持续整理)

    用到过的adb命令都整理下来,省的一直百度,还不一定能找到合适的答案 获得正在运行app的包名 :adb shell dumpsys window | findstr mCurrentFocus 1. ...

  5. 暑期——第五周总结(Web连接hbase数据库)

    所花时间:7天 代码行:1000(python)+250(java) 博客量:1篇 了解到知识点 : 在尝试使用hbase当作数据库时,林子雨老师教程中有完整代码关于使用hbase,我就像当然认为只需 ...

  6. 7.Sentinel源码分析—Sentinel是怎么和控制台通信的?

    这里会介绍: Sentinel会使用多线程的方式实现一个类Reactor的IO模型 Sentinel会使用心跳检测来观察控制台是否正常 Sentinel源码解析系列: 1.Sentinel源码分析-F ...

  7. 夯实Java基础系列9:深入理解Class类和Object类

    目录 Java中Class类及用法 Class类原理 如何获得一个Class类对象 使用Class类的对象来生成目标类的实例 Object类 类构造器public Object(); register ...

  8. 配置Redis(远程访问及授权设置)

    配置Redis(远程访问及授权设置) 1.将redis.conf里面的bind 127.0.0.1这一行注释掉,添加自己服务器的IP 2. 还有,找到protected-mode这行, 将改为yes. ...

  9. 清空div中的数据

    //清空div $("#divinput").val(""); $("#divimg").val(""); $(&quo ...

  10. 【未完成】mysql数据库安全性配置——用户授权

    方式一:从服务设置授权 一:用户授权——从服务设置授权 (1)准备测试环境——不同服务器用户 首先,查看数据库连接当前用户情况,当前连接的只有root用户. select user,host,pass ...