cocos2d-x萌新指南(七)——布置游戏场景、拖动图片

DinS          Written on 2016/4/29

第七话 修炼

“世界的灯,从各地的山隘升起以照耀众生。”

——《神曲》天堂篇1:37-38

一路走来我们学习的都是游戏周边的内容制作,在这一话我们将进入游戏主场景的制作。先来说一下这个游戏怎么玩。从本质上来讲《神曲》是一个拼图游戏,在每一关中给出若干图片,然后根据线索将图片移动到正确的位置。跟其他拼图游戏不同之处在于,《神曲》是意义拼图,即线索给出一段意思,然后玩家根据图片表达的意思进行摆放。游戏界面如下:

为了制作一个完整的游戏场景,依然要请出友伴cocosstudio。首先在studio中进行布局,然后再到程序中完成相关功能。

因为studio对各位来说应该已经基本掌握了,所以这里将从简介绍,主要说明各个控件的名称和将要完成的功能。

首先打开studio,在画布列表中右键->新建画布,如下:

不得不说当年我还不知道这么一回事,所以每当要新建一个场景时我都新建一个项目,而每个项目都要导入资源,这样会有许多相同的资源被导入多次,造成安装包奇大无比。 新建画布则可以使用这个项目中已导入的任何资源,节约空间。

之后就是导入新资源,拖入控件,重命名,摆放、调整……。

首先拖入背景,并拖入一个按钮,负责点击后弹出线索。之后新建一个层放置画框,该层不需要有任何功能所以交互取消掉。之后建立两个层用于放置线索和通关后的说明,这里有按钮响应点击,所以需要勾选交互。最后建立一个层用于放置图片(拼图块),该层的渲染层级小于画框层,二者又都小于线索和通关层。层需要勾选交互,并且特别地因为图片需要响应拖动操作,所以也需要勾选交互。最终效果如下:

另外这里图片名称的pic1-4不仅标明了初始时各个图层的渲染层级,而且跟画框frame1-4对应,这样便于记住哪个图片应该放到哪里。

导出项目并将export里面的Example拷贝到resource文件夹内,跟之前的做法一样。如果点开Example会发现多出了一个文件:

至此应该就明白了这个.ExportJson是什么,就是对应的那个画布,因此在导入到程序时就使用对应的画布名称。

接下来在程序中完成相关工作。仿照选关场景建立新场景Inf_lv1并导入studio文件,在此不再赘述。(不知道的去复习 )效果如下图:

如果你看过了之前的所有教程,那么现在你应该可以独立完成加入背景音乐和点击右上按钮弹出线索对话框的代码,这里也不给出详细的代码了。代码只有自己写过才能真正掌握。

接下来完成关键性的图片拖动功能。从何下手呢?一个自然的反应就是,既然按钮可以通过绑定函数响应,并在触摸结束时执行代码,那么是否可以给图片绑定函数,然后在触摸屏幕时执行代码呢?这个思路非常正确, 下面来具体实现。

在.h文件中的private中声明4个图片对象,以及图片所在的层;在public中声明一个拖动图片的函数。如下:

然后在.cpp中的init()中获取对象,并先给图片pic1绑定函数,如下:

除了控件类型是ImageView外,其他的写法都一样,甚至给图片绑定函数的语句跟给按钮绑定函数的语句一模一样。

之后最关键的函数实现,如下:

你的第一反应肯定是:这么复杂的功能只有两句代码? 真的只有两句。

详细分析一下这两句。首先代码是放在MOVED里面,说明这是拖动时才执行的代码。其次看第一句,auto声明了一个变量point,这个point是什么?看等号后面的语句,getTouchMovePosition(),从描述上讲可以知道这是获取触摸的位置,pic1->调用这个函数就是获取触摸pic1的位置,这是一个坐标。于是整个代码的功能就是获取pic1坐标并记录下来。之后看第二句,setPosition(point)之前碰到过,将对象放置到一个位置,而pic1调用这个函数就是将pic1放置在触摸pic1的坐标位置。两句代码合起来就是将pic1放置于触摸pic1的位置,这就十分简明地完成了拖动效果。 之所以可以如此简明要感谢2d-x提供的函数,我们不需要深入了解背后的原理即可实现想要的效果。效果示意图如下:

你在实际测试中可能也发现了有时候拖动不管用,这是因为pic1的层级最低,而其他图片都是交互,这样就将触屏操作拦截了(看不懂去复习 ),现在我们来解决这个问题并实现其他图片的拖动效果。

第一个想法是每张图片绑定一个拖动函数,这当然可以,不过请回忆我们在选关场景中对弹窗的处理。对,我们改写了函数,增加了一个Layout*参数,并实现了用同一个函数完成不同弹窗的任务,这里可以如法炮制。

具体来说,首先给.h中的MovePic_Callback增加一个参数ImageView* pic。我们传入的图片类型是ImageView*,当然要这么写。整体效果是这样一句代码:

void MovePic_Callback(cocos2d::Ref* pSender, Widget::TouchEventType type, ImageView* pic);

之后在.cpp中将MovePic_Callback改写,增加参数保持与.h中一致,同时把原来的pic1全部替换为参数中的pic。然后在init()中给四张图片绑定函数,注意参数不同:

现在去测试一下,发现4张图片都可以拖动了。但是我们还想进一步改进,我们拖动一张图片后希望这张图片位于渲染层级最高,这样不会被其他图片挡住影响体验。很简单,在BEGAN内部增加调高层级的代码,同时在ENDED增加调低层级的代码即可,整体代码如下:

为什么是1和4?因为pic1-4的渲染层级分别是1-4,而控件渲染层级相同时以最后那个为最高,因此每拖动一张图片该图片层级变为4,而且是最后一个调整的,所以总能处于最高层。当结束时图片变为最低的1不遮挡其他图片。

到目前为止我们已经完成了最基本的拖动功能 ,但是这还远远不够,只能拖动图片不成称为一个游戏,在下一话我们将实现图片嵌入效果以及判定位置是否正确,将会再次提升一个难度,stay tuned.

(注:站长已弃坑,所以该系列不会再更新了,至于下一话的内容,读者根据之前所学一定可以独立完成)