cocos2d-x萌新指南(三)——新建场景、场景转换

DinS          Written on 2016/4/12

第三话 抉择

“从我这里走进苦恼之城,从我这里走进罪恶之渊,从我这里走进幽灵行伍。”

——《神曲》 地狱篇3:1-3

上一话我们完成了主界面的制作,但是游戏不可能只有一个场景,如何增加场景并实现不同场景间的转换呢?这就是本话要完成的任务。

Cocos2d-x官方给出的建议是一个场景一个类,还记得HelloWorld场景吗?这是一个类,也是一个场景,那么一个自然的想法就是照着HelloWorld复刻一个新场景,然后修改新场景的内容。更具体一点就是新建一对.cpp和.h文件。不过这里有个坑 ,这些新文件应该添加到哪里?

通常来说在VS中新建文件的方法如下:

默认位置是proj.win32,但是如果去检查一下Example文件夹会发现AppDelegate和HelloWorldScene是放在class文件夹下,这里的区别很重要。如果放到proj.win32在windows环境下运行没有问题,但是移植的时候会出问题,要把所有程序文件放到class里,所有用到的资源放到resource里。

另外当初我还碰到一个怪事,就是位置这里不能更改,是灰色锁死的。于是我就只能在proj.win32中建立然后手动复制过去。 如果有人遇到这种情况可以这样处理:首先copy一下HelloWorldScene.cpp和.h,改个名字,然后在VS中右键class->添加->现有项,在弹出窗口中选择新复制的文件,这样成功导入VS,然后在VS里再改动。

这里我们新建了一对文件命名为SelectScene,其功能是选择世界。因为我们制作的是《神曲》,但丁游历了地狱、炼狱、天堂,这就是三个子世界,当玩家进入游戏后要选择进入哪个世界。最终效果如下图(空白的是还未解锁的):

从何下手呢?最简单的办法是直接拷贝HelloWorld.h和.cpp的内容,并在其基础上进行修改。具体先看.h文件。

可以对比HelloWorldScene.h看看修改了哪里。最重要的修改是class HelloWorld改成了SelectScene,同时把CREATE_FUNC()里面的HelloWorld改成了SelectScene。这样重新命名后实际上就创建了一个新场景类SelectScene。除此之外还有两处修改,一是删除了原HelloWorld里面的void menuCloseCallback(cocos2d::Ref* pSender)函数,因为用不到。二是将原来的

#ifndef __HELLOWORLD_SCENE_H__

#define __HELLOWORLD_SCENE_H__

#endif // __HELLOWORLD_SCENE_H__

改成了#pragma once,这两者等效,后者是更新的说法,也更简洁。至于这句话是干什么用的可百度之,说得比我专业。

根据要实现的效果可以构思出SelectScene场景包含了4个按钮和1张背景图,3个按钮分别对应地狱、炼狱、天堂场景,1个按钮返回主界面。看过第一话应该知道按钮需要绑定函数,因此4个按钮就需要4个函数,这样需要在.h中进行声明。最终的.h文件见下:

增加了4个转场函数,inCallback指代inferno地狱,puCallback指代purgatory净界,paCallback指代paradise天堂,BackCallback指代返回主界面。确定好.h后开始正式修改.cpp

首先梳理出.cpp的骨架,如下图所示:

跟HelloWorld.cpp没有本质区别,仅在于删除了menuCloseCallback(cocos2d::Ref* pSender)函数并增添了.h中新声明的函数,新添的函数内容可以为空,这样绑定按钮和调试的时候不会报错,此时点击按钮没反应而已。

进入初始化函数进行整体布局,使用的完全是从HelloWorld.cpp中学习的技巧:建立精灵、放置、加入图层,创建按钮、绑定函数、放置,创建menu、加入按钮、放置。以下仅仅给出一个局部,另外两个按钮以此类推。下方的return true是初始化函数的结尾。

注意到backItem的文件来源是UI/,养成素材分类的好习惯。在此补充一下创建按钮时参数的意义,已经标在图上了。记得在resource文件夹内准备相应的图片。此时运行就会得到刚才的效果图,然而我们还没有完成场景转换的任务,接下来进行这项工作。


为了完成场景转化,还是来回顾一下场景是如何创建的,就是通过我们从来没有动过的createScene()函数,说的更具体一点,SelectScene通过SelectScene::createScene()创建场景,HelloWorld通过HelloWorld::createScene()创建场景,因此一个自然的想法是在HelloWorld场景中调用SelectScene::createScene()来完成场景转换。这个思路已经很靠谱了。

现在来具体实现。为了调用SelectScene::createScene(),我们需要在HelloWorld中增加一个按钮,并为其绑定一个转场函数,在该函数中实现转场。因此首先在HelloWorld.h中声明一个函数menuReplaceCallback。这个工作与SelectScene.h中的工作完全一致,实际上就是copy一下改个名字即可,就不在这里贴图了。

然后看.cpp,首先需要引入SelectScene.h,这样使得我们可以使用SelectScene场景类的声明:

其次建立一个按钮并绑定转场函数menuReplaceCallback:

replaceItem的位置摆放到月亮处,我们想让玩家在一开始就寻找如何进入游戏。为此这个按钮不能让玩家看到,如何制作隐藏按钮呢?这里给出的一个傻瓜级方法是图片用透明的,这样自然看不到。这种方法沿用了本系列教程一贯的简单粗暴。 肯定有其他方法,但这种方法依然最直观。不要忘了在menu中加入replaceItem。

于是到了最关键的转场函数的实现方法了,先来看代码:

这里有几个地方需要注意:

1.注意menuReplaceCallback加入的地方和结构。新建的函数与其他函数是并列关系,这里插入在menuCloseCallback的下面。想当初上网找教程,给出的都是独立的代码,我根本不知道加在哪里, 这也是我为什么用截图方式呈现的原因之一。另外一点注意大括号外面没有分号。在c++中每一句代码以分号结束,但这里不需要。还有一点补充说明,这里的函数写法完全沿用了在.h中声明的样子,但是在程序中使用函数时却不能完全照搬这个样子,以后会给出一个具体的例子来说明。这些都属于c++基本常识,因为教程假想的受众是完全没有接触过编程的,如果会最好。如果不会并且感兴趣可以找本c++的书来读。不读也没关系,先照着写写,写多了就懂了。

2.这里虽然只有一行代码,但是比较长,因为这是第一次接触这种样子的代码所以来仔细分析。Director::getInstance()->不需要管,只要记住以后凡是转场代码开头都要加这个就可以了。后面的东西看起来比较乱但是梳理一下会发现3个部分,已经用不同颜色的线条标明。首先来看最外面的replaceScene(),顾名思义就是替换场景,替换成什么场景就是括号里面的内容。其次看中间的TransitionFade::create(),乱就乱在这里,实际上如果只是替换场景不需要加这句,这句的功能是在转换场景时增加一个转场特效:变暗转场。TransitionFade是一种特效,其他的特效可以去官网查看,有了特效转场就不会显得特别突兀,因此还是必要的。现在再来看就比较明白了,创建这个特效需要提供两个参数,这就是create()里面的内容,一个是0.2f,一个是SelectScene::createScene()。前者是特效时间,后者是调用SelectScene场景类里面的创建场景函数,这也是我们最初的思路。整个这句代码的意思就是给SelectScene::createScene()附加一个特效,并使用这种方式替换当前场景。

3.如果你是一个字一个字敲代码的话,等到你输入左括号时会自动有提示告诉你后面要输入的参数以及参数的意义,这是学习的好方式。这也是贴图而不贴代码的另一个原因:多敲代码 。

写完这一句整个主界面就完成了,赶快调试一下吧,当你点击月亮后就会发现顺利转场。恭喜!转场技能get。按照同样的方式将SelectScene里面的返回按钮绑定转场函数,这两个场景就实现了互联,当做一个练习吧。不过要注意这里有个坑,我们设置了进入主界面时播放背景音乐,如果从SelectScene转入主界面会再次执行一遍该代码,你会听到二重奏 。怎么办呢?小提示:在转场函数BackCallback中加入一行停止播放背景音乐的代码即可。

神秘代码:

CocosDenshion::SimpleAudioEngine::getInstance()->stopBackgroundMusic(“sounds/LabyrinthOfDreams.mp3”);

下一话我们要尝试使用更加高效的方式制作新的场景和功能,见《cocos2d-x萌新指南(四)——使用cocosstudio布置场景UI、制作选关界面》。