存档

2013年9月 的存档

CocoaChina大会见闻——cocos2d-x 3.0 新特性

2013年9月27日 没有评论

CocoaChina大会见闻——cocos2d-x 3.0 新特性

1、目的

    参加了CocoaChina大会,感觉内容还是挺多的,具体会议细节大家可以去CocoaChina上看,上面应该有会议记录。写这篇博客主要是整理一下思路,以及面对3.0接下来需要了解的东西。也希望能够帮到大家。

2、大方向

    陈昊芝先生提到了他看来的未来的方向。整个行业趋于规范,营销将具有规模性。游戏中广告获利将是未来获利的一个重点。未来的游戏发展方向是轻量级的游戏天下。同时,游戏市场也将扩大为240亿,其中包含微信的60亿左右。对于多数团队来说,未来赚钱将更难,而坚持做好、做精一款游戏,是一条捷径,因为数量取胜的时代已经过去。随着移动网络的日渐发达,将有更多的用户涌入,上网流量成本的下降,以及网络质量的提高,将会使手机游戏的网络性更加成熟。在客户端方面,陈先生认为,未来是web App与原生并存的模式,游戏营收各半。

3、cocos2d-x 3.0 FrameWork

    这个版本中的改动相当大。我觉得值得注意的地方有以下几个:
  1. c++11 的特性的使用比如Lambda函数,auto等新特性的使用。
  2. 更改了渲染的方式(具体还得再了解,好似是把渲染拆出来了)。
  3. 更改了字体的atlas 渲染方式,提高了多字的渲染效率。
  4. 更改了事件派发,触摸响应不再是注册的顺序进行响应。
  5. 增添了新的GUI。
  6. 编辑器支持:CocoStudio。
  7. 在线更新功能。
    有一些优化是在底层做的,虽然不直接与开发相关,但是也会影响到我们的游戏。除了刚才提到的TTF字体的atlas优化,对于Android的Native Activity也做了优化,极大的提高了android设备上运行的效率。另外更改了Node的排序与增删方式,据说提高了10倍左右的效率。另外应该还有component-entity机制的实现,不过似乎还要花些时间完善。另外toolkit方面要准备出一个cocosInstaller来管理cocos2d-x版本。也将有console命令行工具,估计用上得11月份了吧。有个不太完善的3D extension,据说能做2.5D的游戏了,现在只有场景没完善。现场放了一段动画,看上去很炫的,就是不知性能怎么样。建议大家不要尝试,毕竟未完善的功能会有些潜在的问题的。

4、CocoStudio编辑器

     编辑器作为一个非常重要的元素出现在cocos2d-x3.0中。可以说它是3.0的一部分。编辑器分为UI、场景、动画、数据四个部分。有些引人注目的地方:
  1. GUI支持动画格式。
  2. 多画布的操作。
  3. 支持FLA导入。
  4. 支持ccb文件导入。
  5. 支持PSD、plist导入。
  6. 在场景中使用Entity系统。
  7. 场景可以即时模拟修改,即修改可以马上在模拟器中看到效果。
  8. 支持换装系统,背包系统。
  9. 可以挂载粒子在编辑器中看到效果。
  10. 支持碰撞区域的编辑。
  11. 支持骨骼动画的编辑。
    文档支持方面,据说有个说明文档,还有些实例。刚才找了一圈没太找到。哈 一定是打开方式不正确。

5、总结

      总的来说cocos2d-x这个版本做了很多改进。个人觉得非常是时候。没有过多开发新的功能,潜心优化效率和接口。不冒进,在表面乐观的局势中是很难的,这点我觉得做的很不错。把一些大家都遇到的问题解决好,同时兼容更多的开发方式,才能更好的开发新东西。另外,将CocoStudio作为3.0的一部分也是非常重要的一个思路。这是一个开发方向的问题,优秀编辑器配合可以说是一个相当重要的方面,而先前cocos2d-x缺乏的正是这种支持。所以说,这个版本、这一步cocos2d-x走对了,但是走的好不好还要大家来看。毕竟画出来的饼,只有吃进去才能填饱肚子。



本篇博客出自阿修罗道,转载请注明出处:http://blog.csdn.net/fansongy/article/details/12111581


分类: 未分类 标签:

Xcode cannot run using the selected device after upgrade to Xcode 5.0

2013年9月24日 没有评论

I upgraded to xcode 5.0 today. I then pressed play to run my project in the iOS simulator. This initially worked. Then I decided that I wanted to run the profiler. When I did that, I got the message:

Xcode cannot run using the selected device. 
Choose a destination with a supported architecture in order to run on this device.

I looked at a couple past posts on this problem and decided to do a Clean and Build. Now I can no longer run in the profiler or the simulator. I consistently get the message:

Xcode cannot run using the selected device. 
Choose a destination with a supported architecture in order to run on this device.

How can I resolve this?

Here are various settings:

My Deployment Target is 6.1

Xcode cannot run using the selected device after upgrade to Xcode 5.0

I have also tried changing the deployment target to 7.0, but that did not work either

It appears that the problem is not related to the architecture in the build settings as the error might suggest. Rather, I found that the problem seems to be related to the Build Options Compiler for C/C++/Objective C. I was using a gcc compiler (com.apple.compilers.llvmgcc42) and Xcode 5 has marked this as unsupported.

If I change the compiler to apple’s default Apple LLVM 5.0, the project builds and it can now run in the simulator. The downside is that I have a lot of compiler warnings from code related to cocos2D v1.0 source code. But, at least I have a way forward.

Please follow below step

1>Go to Project Build setting

2>Change compiler for c/c++/objective c as Default compiler(Apple LLVM 5.0) (see in below image)

Xcode cannot run using the selected device after upgrade to Xcode 5.0

I had to change compiler for Default compiler (Apple LLVM 5.0) at two places:

  1. Build Settings > Build Options > Compiler for C/C++/Objective-C (change to LLVM)
  2. Build Rules > Files *.mc using GCC (change to LLVM)

Hard to find because code compiles even if Build Rules point to an undefined compiler.

I had this error when I changed the value of the “Bundle name”-key in the Target Properties. Changing it back to “%{PRODUCT_NAME}” solved the problem for me.

Check that the Executable File (also known as CFBundleExecutable) in the Info.plist file is set to ${EXECUTABLE_NAME} as opposed to any hardcoded value. This will ensure that even if you change your project name or target name or scheme name, that it still works.

After inspecting all the build settings for 15 minutes, this worked for me (Xcode 5.0.2):

Quit and restart Xcode

This issue often occurs after duplicating targets on older projects.

Set the following in your Info.plist for the target:

Bundle Name = ${PRODUCT_NAME}
Bundle Display Name = ${PRODUCT_NAME}
Executable file = ${EXECUTABLE_NAME}

Build and run with these settings, after a successful build they can be changed to anything you want.

This works for me: “Quit and restart Xcode”. I recently updated something and the testing device on Xcode said: ‘iDevice’ not iPhone or iPod. So I restarted then my iPhone came back to the target list.

分类: cocos2d, stackoverflow精选 标签:

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

2013年9月23日 没有评论

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

 

    
大家好,我是红孩儿.经过一年左右业余时间的持续开发,《红孩儿工具箱》已经初步完成了一些不错的功能,大家可以用它来辅助我们基于Cocos2d-x的游戏开发工作,帮助我们提升工作效率,实现一些复杂的场景和动画效果。好啦,废话不多讲,今天我来讲解一下如何使用红孩儿工具箱制作小游戏-《打地鼠》GO

《打地鼠》这个游戏很简单,就是玩家在看到地鼠从土地里钻出来时用挥舞的锤子砸向地鼠就可以了。这个游戏需要做一个简单的场景,然后还需要一些动画,比如地鼠从土里钻出来的动画和锤子落下的动画等,然后还需要有文字显示积分。下面我们来讲解一下如何使用红孩儿工具箱来制做这一切。

一.拼图PLIST生成
     首先我们需要从www.game2z.com  网站,在左上角的 下载红孩儿工具箱最新版 链接处下载最新的0.2.2版本。下载后我们将其解压到自定义的目录。打开后我们可以看到工具箱EXE程序和一个dx9的dll.还有一个资源目录Resource,一个测试设备图片存放目录Dev以及一个配套的SDK目录.红孩儿工具箱只需要这个EXE和对应的这个dll就可以运行在Windows操作系统了.如果你的操作系统中安装了相应的dll,那么也就是说,整个红孩儿工具箱,只需要一个3M多的EXE程序就可以正常运行了.是不是很小巧绿色环保?


    下面我们在工具箱所在目录的资源目录Resource中新建立一个自已的项目资源目录DaDiShu。然后我们从Cocos2d-x的HelloLua工程资源里找到一些农场的图片,还有沙地和植物的图片,把它们拷贝到DaDiShu目录。这将是构成我们场景的重要资源。


使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

 

     我们将它们拷到DaDiShu下。然后启动工具箱,这时我们可以看到红孩儿工具箱的登录界面,我们一般查看可以选择离线登录,但离线登录不能导出动画和场景,主要是用于查看和编辑。如果是想导出,那就最好到www.game2z.com论坛注册一个正式用户的账号。在这里我们输入注册账号和密码后,点击“登录”,稍等片刻完成验证后即可进入工具箱主界面。

     使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

 

    我们首先要做的,是先设置一下我们的工程资源目录,点击“设置工程资源目录”按钮,选择我们的资源目录即可,一旦设置完成,工具箱就会开始遍历和登记工程目录下所有的文件资源,这样我们就可以使用工程资源目录下的图片了.下次再使用工具箱时也会自动的设置好资源目录.
    

    我们首先想做的是把crop.png图片进行碎图PLIST生成。Cocos2d-x是可以识别碎图PLIST文件的,工具箱也可以识别带有PLIST文件的PNG图片来使用碎图设置精灵,我们在工具箱主界面的第一个功能编辑页“拼图/切图”中就可以完成这个需求,“拼图/切图”页默认的是“拼图”导出面板,我们点击一下工具箱全局配置信息下面的“切图/拼图-[拼图”复选框,现在切换为“切图”编辑面板。这时候就可以将图片进行切图操作了。


使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

 

    我们点击“选择图片文件”打开crop.png图片,这时候在工具箱的左边图片元件树控件就会显示出crop这个图片树项,同时在视图窗口中会显示这张图片。如图:

 使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

          我们在左边的crop树项上右键,可以弹出菜单,这时候我们选择一下“按行列数切块”,在弹出的对话框中输入块名称crop,行数填1,列数填4即可,也可以在弹出菜单中选择“固定大小切块”,在弹出的对话框中输入切块宽高和间距边距,确定后我们可以看到在crop树项下生成了相应的图块。这时我们可以选择各树项进行查看,也可以在图片上直接点击显示图块项。

 使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


       我们可以看到相应的图块会显示出调整矩形编辑框,这种方式是可以让我们通过鼠标点中编辑框结点来修改图块的大小和位置的。不过在这里使用行列数切块就不需要调整了,如果小伙伴们有自已的需求,也可以通过对图片项弹出菜单中的“加入新图块”来手动进行图块的切分。

        我们在编辑好图块后,确认一下图片导出的名称和目录,点击“立即导出”,这时工具箱就可以为我们的图片crop生成相应的PLIST。如图:

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


生成的文件:

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


在工具箱后面的场景制做中,我们就可以使用这个PLIST来进行各状态植物图片的摆放。

二。场景编辑

现在我们切换到场景编辑页中,如图:

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


       我们点击“创建”,来新建一个地图,这个《打地鼠》游戏场景不需要滚屏,只有一张背景图farm.jpg大小就可以了,在这里我们输入场景名称farm,场景宽800,高800。然后确定,就创建了场景,我们可以看到主视窗里场景大小的一个边框,我们的场景就是要放在这里面的。如图:

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


      好,我们现在来规划一下这个场景的分层。我们可以将这个场景分为三层,第一层是农场背景,第二层是沙地格子,第三层是植被。这样将沙地格子放在农场背景中,植被放在沙地格子中,就可以实现一个农场的场景了。下面我们来实现一下。

      在右边的面板下部右键弹出菜单,选择“新增地图层”,然后会弹出一个地图层设置的对话框:

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


        我们计划第一层只是放一个农场图片,所以没有必要考虑格子,输入层的名称“BK”后确定即可,之后会增加一个图层页BK,这个图层页中有一个空白树控件,是用来管理放在这一层的各种资源,比如图片,动画,粒子等。


      使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


       我们在这个图层页中资源树区域右键点击,选中弹出菜单“增加新图类”项,选中后会弹出一个图片分类对话框,输入图片类名称“farm”,然后就会有一个图片类树项显示出来,我们可以在这个分类项上点击右键,在弹出菜单里我们可以看到很多可以增加的资源选项,我们在这里只加入一张背景图,所以选择“增加新图片”。

          使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


        在弹出的文件选择对话框中我们找到farm.jpg,然后确定,就可以将农场背景图加入到这一层的资源树中了。需要注意的是在浏览框中文件类型我们要选择jpg格式.因为这个图片是jpg的.


      使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


        我们点击图片项,可以看到在右上角的显示窗口中显示出这个资源项,然后我们把鼠标移动到主视窗中场景左上角附近点击一下,这时农场的背景图就被放入到场景中了。

        使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


         右键取消选中的资源,然后我们点选场景中的这个背景图片,在它被选中后我们在右边面板中点击“物件编辑”切换到物件的位置输入面板,输入位置0,0,就可以使其完全与场景框贴合在一起,这样我们第一层背景图就编辑好了。[为了方便查看,这里我按着Ctrl键的同时用鼠标滚轮缩放视图到合适大小.

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


       下面我们来创建第二层沙土格子的图层,我们在地图层选项页右边空白处右键,在弹出的菜单中选择“新增地图层”:


      使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


    
之后我们可以看到建立新图层的对话框,我们现在要考虑的是对于沙土格子land.png这张图片,他是要基于网格进行拼合的,而它本身是有斜度的。对于有斜度的网格,我们要选择斜视角的观察方式,在这里我们输入格子的宽度为lan.png的宽高182×94,之后输入网格的位置偏移,这个位置偏移就是以场景左上角为起点向右下进行偏移的距离,结果位置将作为第一个格子(0,0)的起点。这个起点在普通观察方式下就是格子的左上角,在斜视角的观察方式下则是格子左角。我们在这里可以输入X偏移30,Y偏移440,然后设置格子的行数为5,列数为3,点击确定后这一层就创建成功了,我们可以选中视图区左上角的“显示格子”看到在场景的相对偏移位置作为起点显示出了53列的斜视角网格。如图:

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

          如果我们觉得格子大小或位置不合适,也可以在相应的图层页项上右键点击,在弹出菜单里点击“修改当前图层”进行反复修改:


    使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


经过反复确认后,偏移位置x设为30,y设为460比较好,能够比较准确的将53列的格子放置在土地区域。

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


   好,我们在这一层的资源树控件中按照之前的方式增加图片类“land”,然后把land.png加入进来选中它,这时候我们就可以在相应的格子上刷图了,我们将鼠标在选中land.png的状态下移到场景中,如果我们选中了视图区左上角的“显示格子”复选框,那么在相应的格子上点击,就会自动在格子中刷上相应的图片。如果我们按下Ctrl键的同时从第1个格子向最后一个格子拖动那么将直接进行区域刷格子。如图:

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

      这样,第二层的沙土格子层我们就创建出来了。现在我们要继续创建植物层,植物层不需要格子,所以和第一层背景的建立方式是一样的,在右边面板选项空白处右键,在弹出的菜单中选择“新增地图层”进入到建立新图层的对话框,输入“OBJ”直接确定就可以。下面我们将crop.png加入到这一层的资源树中,这时我们可以看到它会自动的识别所有的图块。我们可以点击图片crop.png来放到场景中,也可以选中其下的crop_0~4来放入到场景中,在这里我们随便选一些图块放到场景沙土地的相应位置上如图:

     

    使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


   

        现在我们第三层也就做好了,是不是很简单?

        最后我们来生成一些事件点来创建地鼠。因为地鼠是从沙土地上生成出来的,所以这些事件点也就放在格子中,我们在右边面板切换到第二层沙土格子层。在图类上右键,选择弹出菜单项“增加事件格”,取中视图区左上角的“显示格子”复选框,同时为了方便查看,我们可以选择显示方式为“高亮当前层”项,这时候只有当前层的元素是高亮显示的。然后我们在场景沙土地的一些位置点击,把创建地鼠的事件格子编辑好后,切换为“显示所有层”,整个场景就算完成了。如图:


       使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏 

          

三.动画制作

首先我从网上找到老鼠,锤子,金币的图片并将它们用photoshop制做成动画序列图。

图一:地鼠钻出来的序列图

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

图二:锤子落下的序列图

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

图三:金币闪现的序列图

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


    好了,现在我们切换到“切图”面板,然后按照之前crop.png的切图方式来为它们生成相应的plist

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

     现在这些序列图已经有图块Plist了,我们开始为它们制做相就原动画.打开动画编辑面板,我们开始制做相应的序列帧动画.首先我们要建立一个图片结点.图片结点本身就是一个独立的精灵,可以表现动画.我们在左边的结点树控件的Root结点上右键单击,在弹出的菜单中选择“增加图片结点”:

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

     
工具箱在图片结点和骨骼结点的显示图标是可以自定义的,如果没有定义,此时会弹出提示未设置图片结点默认图标的消息框,确定后会弹出相应的设置对话框,这时我们可以选择Resource下的cocos2d-x.pngBone.png来作为图片结点和骨骼结点的默认图标.

    

   使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

        确定后就会出现cocos2d-x.png来显示在视窗的中心点了.

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

     
这时我们在这个图片结点项上右键,在弹出菜单中选择“生成固定帧间隔关键帧动画”就可以为这个图片结点弹出一个设置序列帧动画的对话框.

    使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

    
在“创建固定帧间隔的关键帧动画”对话框中,有两种图片源选取方式,第一种是使用图片序列,就是一般多张图片如attack_0.pngattack_1.pngattack10.png这种多张同名使用不同数字后缀的图片进行生成,因为我们的图片是拼在一起的,所以这里我们选中“使用拼合图内图块序列生成”的方式.之后点击“查找图块”,这时会弹出一个新面板.

    使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

    

    这个新面板是做什么用的呢?它就是图片及动画资源库面板.在这里我们可以点击“导入资源文件到当前资源库中”这个按钮来将我们需要的图片加入.如果有时候我们编辑的时候修改了图片,那也可以在这里随时点击刷新资源文件进行重新加载.

    我们现在将锤子图片导入进来.并选中任意一个图块:

     使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


     
这时候我们可以看到图片和图块都显示正确,然后我们点击“应用此图块”,这时候资源库对话框就消失了,我们会到之前的“创建固定帧间隔的关键帧动画”对话框中.可以看到图块起始为0,图块结束自动变为了2,我们把动画的间隔时间还使用默认的100毫秒,点击确定后,我们可以看到在动画编辑面板下部的帧显示区有3帧被设为了关键帧我们点击他们可以在主视窗中就显示出相应帧的动画了.

    使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


    

      我们可以在下面的帧显示区右部分点击“播放动画”复选框来直接查看动画的播放.并且可以手动随时调节帧间隔的时间来改变动画的速度.

      这样,这个锤子砸下来的动画就做好了.我们保存一下.在弹出的保存文件对话框里我们可以输入attack,格式仍为ani,确定后会再弹出一个修改动画名称的对话框,我们仍然输入attack后确定.这个动画就被保存为attack.ani文件了.同时会导出一个attack.plist.这个plist我们就可以在cocos2d-x中进行播放了.

      使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

       按照上面锤子动画的制做方式我们继续完成老鼠出生的动画和弹出金币的动画,它们对应的图片为laoshu.pngjinbi.png,动画名称可以分别设为borthgoal.导出的动画也就分别是borth.plistgoal.plist.

       现在三个动画和三个序列帧的PLIST就都导出了.我们就把游戏中的场景和动画制做完成了.


四.字图制作

       我们现在还需要一些文字来显示游戏名称和得分.我想做成彩色的文字显示在游戏画面合适的位置.这要用到Cocos2d-x支持的字图.即使用png+fnt的方式显示字库,其中png图片存储文字的显示结果,fnt存储文字的位置信息.强大的红孩儿工具箱也提供了字图的编辑和导出功能.我们来试一下.

        我们现在切换到“字体编辑”面板,然后我们在文档信息框里删除原有文字后输入“打地鼠0123456789”,接下来我们选择自已想要的字体,这里我选的是华文琥珀,字大小为36.确定后我们可以看到文档信息框里文字变成了相应的字体.

         使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


         这时我们点击“开始生成”,即可以很快看到生成出来的字图:


       使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


       这黑黑的文字不是我们想要的,现在我们来进行一下美化,点击右上角“编辑文字效果”按钮切换到编辑文字效果的面板。

     使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


       
这时我们可以选择字体颜色,调节字的间距,以及选一种自已喜欢的阴影方式。之后我们还可以在图片着色部分中加载一张过渡图片来进行着色.比如这里我们使用font_effect1.png来进行单字应用的叠加着色.同时字体用红,阴影用黑,右下描边,阴影粗细填5,间距为1,一个五彩的字图就出现了:

        使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

       

       感觉玩的差不多了,可以点击导出fntpng字图保存为text.pngtext.fnt.这样我们的游戏就可以使用这个字图来进行游戏名称的显示和积分的显示了.

       使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


         

五.粒子制作

       最后,我还想在农场里加入一个雪花落下的粒子效果,这样可以更加增加场景的气氛感。我们切换到工具箱的“粒子编辑”面板。在这里我们可以看到在主视窗中有一个粒子效果。右边面板有一个可以选择的粒子模版库的下拉列表和一些属性值编辑区域

       使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


         
在粒子模版库中放置了一些Cocos2d-x可以支持的粒子系统的样式。我们在这里要做一个下雪的效果,所以直接选择snow就可以了。

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


       我们现在能看到下雪效果的粒子系统了,但是它的粒子是没有贴图的,还只是渐变色块,我们点击“更改图片”就可以找一个球体的图片来做为雪花的贴图。


  使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


         这样漂亮的雪点的效果就出现了。


使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


         我们可以根据需要作改一些属性参数。比如横向的粒子系统宽度和起始颜色。

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


      最后,我们点击“保存”,可以将其保存成snow.plist放在资源目录。

  使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


       
下雪的粒子系统我们就算做好了,下面再切换到场景编辑部分把下雪的粒子系统加入到场景中。直接在第三个图层下的图类项上右键,在弹出菜单中选择“增加粒子系统”,之后将snow.plist导入就可以了。

        使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏


       

    最后保存,并导出地图的XML就完成了场景中的下雪效果

    这样我们就把工具处理部分就算完成了,我们下面进入到代码的编写部分.

六.代码编写

     为了方便工程的建立,我们可以直接将Cocos2d-x中的HelloCpp工程目录复制一份出来,然后修改工程名,之后将工具箱附带SDK中的C++目录中的Map子目录中的代码拷贝到Classes中。

 使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

     然后我们打开工程,将相应文件加入到工程中

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

   

现在我来介绍一下工具箱开源的场景代码,除了解析xml而加入的tinyxml之外,这里主要就是两个类文件


HHRMapLayer.h/cppHHRMapReader.h/cpp,它们分别是显示场景和解析场景文件的类。这两个类文件可以开源的哦~,大家学习之后就可以自行进行扩展并进行二次开发了。

CHHRMapReader
是用于工具箱的地图XML文件的解析,支持多层场景,任意网格设置,摆放图片和粒子系统,设置事件点,路径点。我们可以用工具箱来制做场景,导出成XML格式后用它来进行解析。


头文件代码:

#ifndef _HHRMAPREADER_H
 
#define _HHRMAPREADER_H
 
//==================================================================//
 
//File:        HHRMapReaer.h
 
//Date:        2013-09-05
 
//Auto:        Honghaier 
//Blog:        http://blog.csdn.net/honghaier
 
//Web:        http://www.game2z.com
 
//Desc:        用于红孩儿工具箱的地图解析,目前只支持图片和粒子系统
 
//==================================================================//
 
#include "cocos2d.h"
 
#include "ccTypes.h"
 
#include <stdio.h>
 
#include <string>
 
#include <vector>
 
using namespace std;
 
using namespace cocos2d;
 

#if (CC_TARGET_PLATFORM != CC_PLATFORM_WIN32)
 
//ANDROID平台上用的,用于位置
 
struct POINT
 
{
 
        int         x;
 
        int  y;
 
};
 
#define _MAX_PATH        256
 

#endif
 

#define BREAK_IF(a)                if(!a)break;
 
//地图头信息
 
struct stMapHeader
 
{
 
        int                m_nVersion;                                                        //版本号
 
        string        m_strMapName;                                                //场景名称
 
        int                m_nSceneWidth;                                                //场景宽度
 
        int                m_nSceneHeight;                                                //场景高度
 
        int                m_nLayerNum;                                                //场景层数
 
};
 

//元素类型
 
enum        enuElementType
 
{
 
        RET_NONE         = 0,        //什么也没有
 
        RET_IMAGE         = 1,        //静态图
 
        RET_ANI                 = 2,        //动画
 
        RET_PARTICLE = 3,        //粒子效果
 
        RET_EFFECT         = 4,        //效果
 
        RET_NPC                 = 5,        //角色
 
        RET_OBSTRUCT = 6,        //阻挡格
 
        RET_EVENT         = 7,   //事件格
 
};
 

//精灵扩展类
 
class  CCSpriteEx        :public CCSprite
 
{
 
public:
 
        //取得四边形顶点指针
 
        inline ccV3F_C4B_T2F_Quad* getQuadPtr(void) { return &m_sQuad; }        
 
};
 

//粒子系统扩展类
 
class        CCParticleSystemQuad_Ex        :public CCParticleSystemQuad
 
{
 
public:
 
        //取得PLIST
 
        const char*         getPListPath()
 
        {
 
                return m_sPlistFile.c_str();
 
        }
 
        //打开相应的粒子PLIST文件
 
        bool  LoadParticleInfoFromPListFile(const char* szPListFile)
 
        {
 
                return initWithFile(szPListFile);
 
        }
 
};
 

//资源信息
 
struct stMapResInfo
 
{
 
        enuElementType                                m_Type;                                                //类型
 
        string                                                m_strFileName;                                //文件名(图片名,动画PLIST名或粒子系统PLIST名)
 
        string                                                m_strBlockName;                                //图块名
 
        CCSpriteEx*                                        m_pSprite;                                        //精灵
 
        CCParticleSystemQuad_Ex*        m_pParticleSystem;                        //粒子系统
 
};
 

//批次结点处理
 
struct stBatchNodeInfo
 
{
 
        string                                m_strFileName;                //文件名(图片名)
 
        CCSpriteBatchNode*        m_pBatchNode;
 
}
 
;
 

//视角
 
enum enuViewType
 
{
 
        VT_NORMAL                = 0,        //普通
 
        VT_SKEW                        = 1,        //斜视角
 
        VT_FREE                        = 2,        //不使用格子
 
};
 

//自由物体
 
struct stFreeObj
 
{
 
        stMapResInfo*        m_pResInfo;                                //对应的资源索引
 
        CCSprite*                m_pSprite;                                //排序时加入的精灵
 
        float                        m_fPosX;                                //X位置
 
        float                        m_fPosY;                                //Y位置
 
        float                        m_fLowerHeight;                        //最低位置(用于排序)
 
};
 

//路径
 
struct stPathNode
 
{
 
        bool                        m_bIsTile;                                //是否是格子
 
        POINT                        m_sSrcTile;                                //起点格子,如果是格子,则为格子位置,否则为像素位置
 
        POINT                        m_sDestTile;                        //终点格子,如果是格子,则为格子位置,否则为像素位置
 
}
 
;
 

//事件
 
struct stEventTile
 
{
 
        int                                m_nEventID;                                //事件ID
 
        bool                        m_bIsTile;                                //是否是格子
 
        POINT                        m_sTile;                                //如果是格子,则为格子位置,否则为像素位置
 
};
 

//层结构
 
struct stMapLayerInfo
 
{        
 
        enuViewType                        m_ViewType;                        //视角
 
        int                                        m_nTileWidth;                //格子宽度
 
        int                                        m_nTileHeight;                //格子高度
 
        int                                        m_nTileRows;                //格子行数
 
        int                                        m_nTileCows;                //格子列数
 
        int                                        m_nStartPosX;                //横向格子起点位置
 
        int                                        m_nStartPosY;                //纵向格子起点位置
 
        stMapResInfo**                m_pTileResArray;        //格子对应资源索引
 
        vector<stFreeObj>        m_ObjectVec;                //自由物体容器
 
        int                                        m_ObjectNum;                //自由物体数量
 
        vector<stPathNode>        m_PathNodeVec;                //路径容器
 
        int                                        m_PathNodeNum;                //路径点数量
 
        vector<stEventTile> m_EventTileVec;                //事件容器
 
        int                                        m_EventTileNum;                //事件点数量
 
};
 

//地图解析类
 
class CHHRMapReader
 
{
 
public:
 
        //构造
 
        CHHRMapReader();
 
        //析构
 
        ~CHHRMapReader();
 

public:
 
        //从文件中载入地图
 
        bool                        LoadDataFromFile(const char* szFileName);
 
        //从内存中载入地图
 
        bool                        LoadDataFromData(const char* szData);
 
        //清空
 
        void                        CleanUp();
 

public:
 

        //取得场景头信息
 
        stMapHeader*        GetMapHeader();
 
        //取得资源数量
 
        int                                GetResInfoNum();
 
        //取得资源指针
 
        stMapResInfo*        GetResInfoPtr(int vIndex);
 

        //取得层数量
 
        int                                GetLayerInfoNum();
 
        //取得层信息指针
 
        stMapLayerInfo*        GetLayerInfoPtr(int vLayerIndex);
 

        //取得相应格子的资源数据
 
        stMapResInfo*        GetTileResData(int vLayerIndex,int vTileX,int vTileY);
 
        
 
        //取得对应层的自由物体数量
 
        int                                GetLayerFreeObjNum(int vLayerIndex);
 
        //取得对应层的自由物体
 
        stFreeObj*                GetLayerFreeObj(int vLayerIndex,int vObjIndex);
 
        
 
        //取得路径数量
 
        int                                GetLayerPathNodeNum(int vLayerIndex);
 
        //取得对应层的制定路径
 
        stPathNode*                GetLayerPathNode(int vLayerIndex,int vPathNodeIndex);
 

        //取得指定格子是分支路径起点的分支路径数量
 
        int                                GetNextPathNodeNum(int vLayerIndex,int vTileX,int vTileY,vector<int>& vNextPathNodeVec);
 

        //取得事件点数量
 
        int                                GetLayerEventTileNum(int vLayerIndex);
 
        //取得对应层的事件点
 
        stEventTile*        GetLayerEventTile(int vLayerIndex,int vEventTileIndex);
 


private:
 
        //头信息
 
        stMapHeader                                                m_MapHeader;
 
        //资源信息容器
 
        vector<stMapResInfo>                        m_MapResInfoVec;
 
        //地图层信息容器
 
        vector<stMapLayerInfo>                        m_MapLayerInfoVec;
 
        //批次结点信息
 
        vector<stBatchNodeInfo>                        m_SpriteBatchNode;
 

};
 

#endif

        从这个文件里我们可以看到CHHRMapReader能够从XML场景信息文件中读取场景信息,层数,网格信息,自由物体信息,路径信息,以及事件点信息,很多信息都是基于图层索引来获取的,这样是为了适应工具箱的多层随意网格的特性。

        CHHRMapLayer是用于使用Cocos2d-x进行场景显示的类。他本身就可以显示出XML地图了。

#ifndef _HHRMAPLAYER_H
 
#define _HHRMAPLAYER_H
 
//==================================================================//
 
//File:        HHRMapLayer.h
 
//Date:        2013-09-05
 
//Auto:        Honghaier 
//Blog:        http://blog.csdn.net/honghaier
 
//Web:        http://www.game2z.com
 
//Desc:        用于红孩儿工具箱的地图显示,目前只支持图片和粒子系统
 
//==================================================================//
 
#include "HHRMapReader.h"
 
using namespace std;
 
USING_NS_CC;
 

//场景的精灵
 
struct stHHRMapSprite
 
{
 
        CCSprite*                                m_Sprite;
 
        CCPoint                                        m_sPosition;                        //位置
 
};
 
//场景的精灵层
 
struct stHHRMapSpriteLayer
 
{
 
        vector<stHHRMapSprite*>        m_MapSpriteVec;                        //精灵
 
};
 

//红孩儿工具箱的地图层显示
 
class CHHRMapLayer        :public        CCLayer
 
{
 
public:
 
        //构造
 
        CHHRMapLayer();
 
        //析构
 
        ~CHHRMapLayer();
 

public:
 
        //加载场景XML文件
 
        bool                                LoadHHRMap(const char* szFileName);
 
        //地图读取器
 
        CHHRMapReader*                GetMapRender();
 
        //设置观察点
 
        void                                SetCameraPos(float fX,float fY);
 
        //取得摄像机的当前位置
 
        CCPoint                                GetCameraPosition();
 
        //移动摄像机的位置
 
        void                                MoveCamera(float vOffsetX,float vOffsetY);
 

        //通过位置取得格子
 
        POINT                                GetClickTile(int vLayerIndex,int vPosX,int vPosY);
 
        //通过格子取得位置(格子中心点位置)
 
        CCPoint                                GetTileCenterPos(int vLayerIndex,int vTileX,int vTileY,bool bIsScreenPos = true);
 

        //放入一个新的精灵到一个格子上
 
        stHHRMapSprite*                AddSpriteToTile(CCSprite*        pSprite,int vShowIndex,int vLayerIndex,int vTileX,int vTileY);
 
        //放入一个新的精灵到场景中
 
        stHHRMapSprite*                AddSpriteToMap(CCSprite*        pSprite,int vShowIndex,int vPosX,int vPosY);
 
        //开启精灵的动画播放
 
        void                                RunSpriteAction(CCSprite*        pSprite);
 
        //取得放入的精灵数量
 
        int                                        GetSpriteNum(int vLayerIndex);
 
        //取得指定的精灵
 
        stHHRMapSprite*                GetSprite(int vLayerIndex,int vSpriteIndex);
 
        //删除指定的精灵
 
        void                                DelSprite(CCSprite*        pSprite);
 
        //删除所有的精灵
 
        void                                DelAllSprites();
 

        //设置使用按下拖放
 
        void                                SetTouchDrag(bool bTouchDrag);
 

public:
 
        //渲染
 
        virtual void                draw(void);
 
        //加载时调用
 
        virtual void                onEnter();
 
        //释放时调用
 
        virtual void        onExit();
 
        //响应触屏事件处理
 
        virtual void                ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
 
        virtual void                ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);
 
        virtual void                ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);
 
        virtual CCObject*        copyWithZone(CCZone *pZone);
 
        virtual void                touchDelegateRetain();
 
        virtual void                touchDelegateRelease();
 

private:
 

        //更新场景
 
        void                                UpdateScene();
 
        //渲染指定格子
 
        void                                RenderTile(int vLayerIndex,int vTileX,int vTileY,ccColor4B color);
 
        //渲染对应的图素
 
        void                                RenderElement(enuViewType        vCameraType,CCSize        vTileSize,stMapResInfo*        pRenderInfo,float vPosX,float vPosY,float vPosZ);
 

private:
 

        //地图读取器
 
        CHHRMapReader                                m_MapReader;
 
        //当前放在场景层中的精灵
 
        vector<stHHRMapSpriteLayer>        m_SpriteLayerVec;
 
        //当前观察点
 
        CCPoint                                                m_sCameraPos;
 
        //按下时记录上一个点的位置
 
        CCPoint                                                m_sTouchLastPos;
 
        //是否响应拖动处理
 
        bool                                                m_bTouchDrag;
 
        //上次更新的时间                
        double                                                m_dwLastTime;
 
        //错误返回字符串
 
        string                                                m_ErrorStr ;
 
}        
 
;
 
#endif

         从这个代码中我们可以看到CHHRMapLayer就是一个CCLayer,它拥有CCLayer的特性,可以直接放在场景中进行显示。它还可以进行进行格子的获取以及将一个精灵放置在格子上。

        我们这现在就使用这两个类来进行《打地鼠》的制做。

         我们打开HelloWorldScene.h,在这里引入”HHRMapLayer.h”,并为HelloWorld创建一个地图显示层的成员指针用于实例化这个地图显示层。并加入基于鼠标位置显示在屏幕上的锤子精灵以及显示分数的字图文字标签。

#ifndef __HELLOWORLD_SCENE_H__
 
#define __HELLOWORLD_SCENE_H__
 
#include "cocos2d.h"
 
#include "HHRMapLayer.h"
 

class HelloWorld : public cocos2d::CCLayer
 
{
 

public:
 
    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
 
    virtual bool init();  
 

    // there's no 'id' in cpp, so we recommend returning the class instance pointer
 
    static cocos2d::CCScene* scene();
 
    
    // a selector callback
 
    void menuCloseCallback(CCObject* pSender);
 

        //老鼠出生的回调函数
 
        void LaoShuBorth(float dt);
 

        //渲染
 
        virtual void                draw(void);
 
        //响应触屏事件处理
 
        virtual void                ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
 
        //删除精灵
 
        void                                DelSpriteFunc(CCNode* pTarget);
 
protected:
 
        //地图显示层
 
        CHHRMapLayer*                m_pHHRMapLayer;                        
 
        //锤子
 
        CCSprite*                        m_pChuiZiSprite;
 
    //计分器
 
        CCLabelBMFont*                m_pCountLabel;
 
        //计数
 
        int                                        m_nAttackMouseCount;
 

    CREATE_FUNC(HelloWorld);
 
};
 


#endif // __HELLOWORLD_SCENE_H__

       然后我们打开HelloWorldScene.cpp,在HelloWorld::init函数中加载地图并创建相应的精灵

// on "init" you need to initialize your instance
 
bool HelloWorld::init()
 
{
 
    //////////////////////////////
 
    // 1. super init first
 
    if ( !CCLayer::init() )
 
    {
 
        return false;
 
    }
 
    
    CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
 
    CCPoint origin = CCDirector::sharedDirector()->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
 
    CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
 
                                        "CloseNormal.png",
 
                                        "CloseSelected.png",
 
                                        this,
 
                                        menu_selector(HelloWorld::menuCloseCallback));
 
    
        pCloseItem->setPosition(ccp(origin.x + visibleSize.width - pCloseItem->getContentSize().width/2 ,
 
                                origin.y + pCloseItem->getContentSize().height/2));
 

    // create menu, it's an autorelease object
 
    CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
 
    pMenu->setPosition(CCPointZero);
 
    this->addChild(pMenu, 1);
 


        //因为我们要显示的文字是汉字,所以为了避免乱码,我们在这里将文字存入到XML中,然后在Cocos2d-x中读取。
 
        CCDictionary *strings = CCDictionary::createWithContentsOfFile("string.plist"); 
        const char *title = ((CCString*)strings->objectForKey("title"))->m_sString.c_str(); 
        CCLabelBMFont* pLable = CCLabelBMFont::create(title, "text.fnt");
 
    pLable->setPosition(ccp(visibleSize.width - 120, visibleSize.height - 100));
 
    this->addChild(pLable,1);
 

        //显示计数
 
        m_pCountLabel = CCLabelBMFont::create("0", "text.fnt");
 
    m_pCountLabel->setPosition(ccp(visibleSize.width - 120, visibleSize.height - 200));
 
    this->addChild(m_pCountLabel,1);
 
        m_nAttackMouseCount = 0;
 
        //-===载入地图=========================================
 
        m_pHHRMapLayer = new CHHRMapLayer();
 
        if(true == m_pHHRMapLayer->LoadHHRMap("park.xml"))
 
        {
 
                m_pHHRMapLayer->autorelease();
 
                addChild(m_pHHRMapLayer,0,0);
 
                m_pHHRMapLayer->SetTouchDrag(false);
 
        }
 
        else
 
        {
 
                delete m_pHHRMapLayer ;
 
                m_pHHRMapLayer = NULL;
 
        }
 

        CCSpriteFrameCache *frameCache = CCSpriteFrameCache::sharedSpriteFrameCache();
 
        //锤子的拼图
 
        frameCache->addSpriteFramesWithFile("chuizi.plist");
 
        //老鼠的拼图
 
        frameCache->addSpriteFramesWithFile("laoshu.plist");
 
        //金币的拼图
 
        frameCache->addSpriteFramesWithFile("jinbi.plist");
 

        CCAnimationCache::purgeSharedAnimationCache();
 
        CCAnimationCache *animCache = CCAnimationCache::sharedAnimationCache();
 


        //老鼠出现的动画
 
        animCache->addAnimationsWithFile("dishu_borth.plist");
 
        //锤子击打的动画
 
        animCache->addAnimationsWithFile("attack.plist");
 
        //金币弹出奖励的动画
 
        animCache->addAnimationsWithFile("jiangli.plist");
 

        //锤子
 
        m_pChuiZiSprite = CCSprite::create();
 
        CCSpriteFrame *frame = frameCache->spriteFrameByName("ChuiZi_0");
 
        m_pChuiZiSprite->setDisplayFrame(frame);
 
        m_pChuiZiSprite->setAnchorPoint(ccp(0.8,0.2));
 
        addChild(m_pChuiZiSprite);
 
        //每2秒出现一只老鼠
 
        schedule(schedule_selector(HelloWorld::LaoShuBorth), 2.0f);
 

        srand(time(0));
 
        //设置可以触屏响应
 
        setTouchEnabled(true);
 
        SimpleAudioEngine::sharedEngine()->preloadEffect("hit.mp3");
 
    return true;
 
}

       首先是创建了一个显示《打地鼠》标题的文字标签,然后是显示计数的文字标签。在这里我们使用了中文,为了避免因编码显示错乱,我们创建了一个XML文件string.plist来使用UTF8存储文字“打地鼠”并在Cocos2d-x中使用。

     

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

     

       随后我们实例化地图层,并调用其LoadHHRMap来加载一个工具箱导出的XML地图文件。再后面就是将拼图PLIST和动画PLIST加载进来,创建锤子精灵和动画,设定一个定时器,每2秒调用一次回调函数LaoShuBorth,哈哈,我那烂烂的E语。为了更加生动,我们在这里还预加入一个音乐文件hit.map来播放击中老鼠时的音效。

       之后我们来编写LaoShuBorth,它每2秒被回调的时候,我们可以创建老鼠的精灵和动画并放入到场景的相应事件点格子位置就可以了。事件点即可以基于格子,也可以基于像素,这个最好在代码中判断一下。

    

void HelloWorld::LaoShuBorth(float dt)
 
{
 
        if(m_pHHRMapLayer)
 
        {
 
                CHHRMapReader*        tpMapReader = m_pHHRMapLayer->GetMapRender();
 
                if( tpMapReader )
 
                {
 
                        int                nEventTileNum                = tpMapReader->GetLayerEventTileNum(1);
 
                        int                nEventTileIndex                = rand() % nEventTileNum ;
 
                        stEventTile*        pEventTile        = tpMapReader->GetLayerEventTile(1,nEventTileIndex);
 
                        if(pEventTile->m_bIsTile)
 
                        {
 
                                //取得事件ID
 
                                int nEventID = pEventTile->m_nEventID ;
 

                                CCSpriteFrameCache *frameCache = CCSpriteFrameCache::sharedSpriteFrameCache();
 

                                CCSprite *dishu = CCSprite::create();
 
                                CCSpriteFrame *frame = frameCache->spriteFrameByName("dishu_0");
 
                                dishu->setDisplayFrame(frame);
 
                                CCSize winSize = CCDirector::sharedDirector()->getWinSize();
 
                                dishu->setAnchorPoint(ccp(0.5,0.0));
 
                                m_pHHRMapLayer->AddSpriteToTile(dishu,1,1,pEventTile->m_sTile.x,pEventTile->m_sTile.y);
 

                                CCAnimationCache *animCache = CCAnimationCache::sharedAnimationCache();
 
                                CCAnimation *Borth = animCache->animationByName("borth");
 
                                Borth->setRestoreOriginalFrame(true);
 
                                CCAnimate *BorthAni = CCAnimate::create(Borth);
 
                                // run the animation
 


                                dishu->runAction( CCSequence::create( BorthAni,  CCCallFuncN::create(this, callfuncN_selector(HelloWorld::DelSpriteFunc)),NULL));
 
                                m_pHHRMapLayer->RunSpriteAction(dishu);
 
                                //由场景层管理,不需要放入当前层
 
                                //addChild(dishu);
 
                        }
 
                }
 
        }
 
        
 
}

    这里要注意的是,如果我们放入一个精灵到地图中,我们调用地图层的AddSpriteToTile函数,但如果这个精灵本身是个序列帧动画,我们还要在它runAction之后再调用一下地图层的RunSpriteAction
保证它被更新播放。在给它运行一个动画时,最好放入一个动画序列,在这个动画序列的最后再调用一个删除精灵的回调函数以保证精灵可以在合适的时机释放。

//删除精灵
 
void        HelloWorld::DelSpriteFunc(CCNode* pTarget)
 
{
 
        if(m_pHHRMapLayer)
 
        {
 
                CCSprite        *pMouseSprite = dynamic_cast<CCSprite*>(pTarget);
 
                if(pMouseSprite)
 
                {
 
                                m_pHHRMapLayer->DelSprite(pMouseSprite);
 
                }
 
        }
 
}

     这样我们运行一下就可以看到我们前面用工具箱制做的地图了,也可以发现每2秒会从事件点对应的沙地格子上生成一个老鼠。

     现在我们希望在鼠标移动时,锤子能跟随移动,怎么做呢?我们需要重载一下HelloWorlddraw函数,并在此中加入获取鼠标位置的代码,然后将鼠标位置设置给锺子。

//渲染
 
void HelloWorld::draw(void)
 
{
 
        
 
        POINT        tCurrPos;
 
        ::GetCursorPos(&tCurrPos);
 
        CCEGLView*        pGELView = CCDirector::sharedDirector()->getOpenGLView();
 
        ::ScreenToClient(pGELView->getHWnd(),&tCurrPos);
 
        if(m_pChuiZiSprite)
 
        {
 
                CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
 
                m_pChuiZiSprite->setPosition(ccp(tCurrPos.x/pGELView->getFrameZoomFactor() ,visibleSize.height - tCurrPos.y/pGELView->getFrameZoomFactor()));
 
        }
 

        CCLayer::draw();
 
}

    下面就只有点击鼠标时,播放锤子打击老鼠时弹出金币,和加分的处理了,在Cocos2d-x中我们可以重载HelloWorldccTouchesBegan函数来实现对鼠标按下的响应并设置HelloWorld层开启触屏事件响应。如果是在手机或Pad上,那就是我们点击屏幕时的响应函数。

        

//响应触屏事件处理
 
void HelloWorld::ccTouchesBegan(CCSet *pTouches, CCEvent* event)
 
{
 
        CCSetIterator iter = pTouches->begin();
 
        for (; iter != pTouches->end(); iter++)
 
        {
 
                CCTouch* pTouch = (CCTouch*)(*iter);
 
                CCPoint        tClickPt = pTouch->getLocation();
 


                CCAnimationCache *animCache = CCAnimationCache::sharedAnimationCache();
 
                CCAnimation *Borth = animCache->animationByName("chuizi");
 
                Borth->setRestoreOriginalFrame(true);
 
                CCAnimate *AttackAni = CCAnimate::create(Borth);
 
                // 运行击打动画
 
                m_pChuiZiSprite->runAction(AttackAni);
 

                // 点击位置,做一个(100,50)的偏移,将攻击点移到锤子头部位置附近
 
                POINT        tCurrPoint;
 
                tCurrPoint.x = tClickPt.x ;
 
                tCurrPoint.y = tClickPt.y ;
 

                CCPoint        tCameraPos = m_pHHRMapLayer->GetCameraPosition();
 
                //击中的老鼠
 
                int                nLaoShuNum = m_pHHRMapLayer->GetSpriteNum(1);
 
                for(int s = 0 ; s < nLaoShuNum ; s++)
 
                {
 
                        stHHRMapSprite*                tpHHRMapSprite = m_pHHRMapLayer->GetSprite(1,s);
 
                        if(tpHHRMapSprite)
 
                        {
 
                                if(tpHHRMapSprite->m_Sprite)
 
                                {
 
                                        int nScreenPosX = tpHHRMapSprite->m_sPosition.x - tCameraPos.x;
 
                                        int nScreenPosY = tpHHRMapSprite->m_sPosition.y - tCameraPos.y;
 

                                        RECT tClickRect;
 
                                        tClickRect.left                = nScreenPosX ;
 
                                        tClickRect.top                = nScreenPosY ;
 
                                        tClickRect.right        = nScreenPosX + tpHHRMapSprite->m_Sprite->getContentSize().width ;
 
                                        tClickRect.bottom        = nScreenPosY + tpHHRMapSprite->m_Sprite->getContentSize().height;
 

                                        if(PtInRect(&tClickRect,tCurrPoint))
 
                                        {
 
                                                m_pHHRMapLayer->DelSprite(tpHHRMapSprite->m_Sprite);
 
                                                m_nAttackMouseCount++;
 
                                                char szTemp[10];
 
                                                sprintf(szTemp,"%d",m_nAttackMouseCount);
 
                                                m_pCountLabel->setString(szTemp);
 
                                                SimpleAudioEngine::sharedEngine()->playEffect("hit.mp3");
 
                                                
 
                                                //击中的格子
 
                                                POINT        tClickTile = m_pHHRMapLayer->GetClickTile(1,nScreenPosX,nScreenPosY);
 
                                                if(tClickTile.x >= 0 && tClickTile.y >= 0)
 
                                                {
 
                                                        CCSpriteFrameCache *frameCache = CCSpriteFrameCache::sharedSpriteFrameCache();
 

                                                        CCSprite *jinbi = CCSprite::create();
 
                                                        CCSpriteFrame *frame = frameCache->spriteFrameByName("JinBi_0");
 
                                                        jinbi->setDisplayFrame(frame);
 
                                                        CCSize winSize = CCDirector::sharedDirector()->getWinSize();
 
                                                        jinbi->setAnchorPoint(ccp(0.5,0.0));
 

                                                        m_pHHRMapLayer->AddSpriteToTile(jinbi,2,1,tClickTile.x,tClickTile.y);
 

                                                        //跳金币动画
 
                                                        CCAnimationCache *animCache = CCAnimationCache::sharedAnimationCache();
 
                                                        CCAnimation *pAnimation = animCache->animationByName("jiangli");
 
                                                        Borth->setRestoreOriginalFrame(true);
 
                                                        CCAnimate *JiangLiAni = CCAnimate::create(pAnimation);
 
                                                        //渐隐消失动画
 
                                                        CCActionInterval*  action1 = CCFadeOut::create(1.0f);
 
                                                        //运行动画序列,先跳金币后消失
 
                                                        jinbi->runAction( CCSequence::create( JiangLiAni, action1,  CCCallFuncN::create(this, callfuncN_selector(HelloWorld::DelSpriteFunc)),NULL));
 
                                                        //设置这个精灵运行动画
 
                                                        m_pHHRMapLayer->RunSpriteAction(jinbi);
 
                                                }
 
                                                
 
                                                break;
 
                                        }
 
                                }
 
                        }
 
                }
 

        }
 

}        

          

       这里面的代码较多,主要流程就是先获取到鼠标点位置,然后遍历场景中的所有地鼠的精灵,之后通过点与矩形的位置判断来确定是否击中地鼠。如果击中,增加分数并播放地鼠的精灵并播放击中的音效。同时在相应的格子上创建金币的精灵动画并播放。

       好了,这样《打地鼠》游戏就算完成了,运行一下,嘿嘿,还不错嘛~

使用《红孩儿工具箱》开发基于Cocos2d-x的《打地鼠》游戏

结束语

谢谢大家的对工具箱的支持和关注,我会继续完善工具箱并编写更多的游戏实例。敬请期待!

另外有任何关于工具箱的问题可以到http://www.game2z.com工具箱专版与我进行交流!

我的新浪微博:http://weibo.com/u/1834515945 工具箱用户群:20970366

分类: cocos2d-x 标签:

iPhone OpenGL ES 2.0 blending with Cocos2D gives unexpected results

2013年9月11日 没有评论

I have very simple CCScene with ONLY 1 CCLayer containing:

  1. CCSprite for background with standard blending mode
  2. CCRenderTexture to draw paint brushes, with its sprite attached to root CCLayer above background sprite:
_bgSprite = [CCSprite spriteWithFile:backgroundPath];
_renderTexture = [CCRenderTexture renderTextureWithWidth:self.contentSize.width height:self.contentSize.height];
[_renderTexture.sprite setBlendFunc:(ccBlendFunc){GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}];
[self addChild:_bgSprite z:-100];
[self addChild:_renderTexture];

Brush rendering code:

[_renderTexture begin];
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE); // 1.
// calculate vertices code,etc...
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)count);
[_renderTexture end];

When user brushes with first colored brush, it blends with background as expected.
But when when continues brushing with another color on top of the previous brush, it goes wrong (soft alpha edges loses opacity when 2 brushes overlap each other):

iPhone OpenGL ES 2.0 blending with Cocos2D gives unexpected results

I tried many blending options but somehow I cannot find correct one.

Is there something special about CCRenderTexture that it does not blend with itself (with previously drawn content) as expected?

My fragment shader used for brushing is just standard texture shader with minor change to preserve input color alpha in texture:

void main()
{
    gl_FragColor = texture2D(u_texture, v_texCoord);
    gl_FragColor.a = v_fragmentColor.a;
}

UPDATE – ALMOST PERFECT SOLUTION : by jozxyqk

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                        GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

in rendering code (in place of // 1. and

[_renderTexture.sprite setBlendFunc:(ccBlendFunc){GL_ONE, GL_ONE_MINUS_SRC_ALPHA}];

THIS WORKS GREAT AND GIVES ME WHAT I WANT…

iPhone OpenGL ES 2.0 blending with Cocos2D gives unexpected results

…BUT ONLY WHEN _rederTexture is in full opacity.

When opacity of _rendertexture.sprite is lowered, brushes get lightened up instead of fading out as one could expect:

iPhone OpenGL ES 2.0 blending with Cocos2D gives unexpected results

Why alphas of the brushes are blending with background correctly when parent texture is in full opacity but go bananas when opacity is lowered? How can I make brushes to blend with background correctly?

EDIT

Blending brush -> layer -> background

OK, what’s happening is glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) is working for blending the brush strokes into the brush texture, but the resulting alpha values in the texture are wrong. Each added fragment needs to 1. add it’s alpha to the final alpha value – it has to remove exactly that much light for the interaction and 2. scale the previous alpha by the remainder – previous surfaces reduce the light by the previous value, but since a new surface is added there is less light for them to reduce. I’m not sure if that made sense but it leads to this…

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                    GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

Now the colour channel of the brush texture contains the total colour to be blended with the background (pre-multiplied with alpha) and the alpha channel gives the weight (or the amount the colour obscures the background). Since the colour is pre-multiplied with alpha, the default RenderTexture blending GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA scales with alpha again and hence darkens the overall colour. You now need to blend the brush texture with the background using the following function, which I gather must be set in Cocos2D:

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

Hopefully this is possible. I haven’t given a lot of thought on how to manage the possibility of setting up the brush texture to blend with GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA but it may require a floating point texture and/or an extra pass to divide/normalize the alpha, which sounds painful.

Alternatively, splat the background into your render texture before drawing and keep the lot there without any blending of layers.

This worked for me:

glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);

fbo.bind();
glClear(GL_COLOR_BUFFER_BIT);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                    GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
drawTexture(brush1);
drawTexture(brush2);
fbo.unbind();

drawTexture(grassTex); //tex alpha is 1.0, so blending doesn't affect background
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
drawTexture(fbo.getColour(0)); //blend in the brush layer

iPhone OpenGL ES 2.0 blending with Cocos2D gives unexpected results

Brush layer opacity

Using GL_ONE, GL_ONE_MINUS_SRC_ALPHA causes issues with the library’s implementation of opacity in layer blending since it assumes the colour is multiplied by alpha. By reducing the opacity value, the alpha of the brush layer is scaled down during blending. GL_ONE_MINUS_SRC_ALPHA then causes the amount of background colour to increase, however GL_ONE sums 100% of the brush layer and oversaturates the image.

The simplest solution imo is to find a way to scale down the colour by the global layer opacity yourself and continue to use GL_ONE, GL_ONE_MINUS_SRC_ALPHA.

  • Actually using GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_ALPHA might be an answer if the library supported it, but apparently it doesn’t.
  • You could use fixed pipeline rendering to scale the colour: glColor4f(opacity, opacity, opacity, opacity), but this will require a second render target and doing the blend manually, similarly to the code above, where you draw a full screen quad once for the background and again for the brush layer.
  • If you’re doing the blend manually it would be more robust to use a fragment shader instead of the glColor method. This would allow far greater control if you ever wanted to play with more complex blending functions, especially where divisions and temporaries outside the 0 to 1 range are concerned:
    gl_FragColour = texture(brushTexture, coord) * layerOpacity;

END EDIT


The standard alpha blending function is glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);, not quite the GL “initial”/default function.

Summing alpha values as you do in glBlendFuncSeparate will oversaturate alpha and the underneath colour is completely replaced. Saturation blending may give decent results: glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE). It might also be worth experimenting with glBlendEquationSeparate and MAX blending, if it’s supported. The advantage of playing with MAX would be reducing the overlapping artefacts (hard triangular bits) from your line drawing code – eg replace colour, but only until total alpha value X is reached. EDIT: Both cases will require blending and clearing after each stroke.

I can only assume blending the render texture onto the background is in fact working. (not for the current layer values)

On a side note and largely unrelated there’s also “Under Blending”, where you keep a transmittance value instead of alpha/opacity (from here):

glBlendEquation(GL_FUNC_ADD); 
glBlendFuncSeparate(GL_DST_ALPHA, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); 
分类: cocos2d, stackoverflow精选 标签:

Cocos2d-x – how to set part of CCLayer transparent?

2013年9月7日 没有评论

I’m newbie in cocos2d-x and I need your help.

I need to make transparent a touched portion of the layer.

How to make a portion of the layer transparent? I had thought to use ССClippingNode, but I’m not find examples or docs.

I use C++. Thanks.

In TestCpp, project that was added to all cocos2d-x version, you can find examples of CCClipingNode.

If you want to hide part of CCNode(for example “layer”) using CCClipingNode, you should add your layer to CCClipingNode.

This is the example that you can paste in the HelloWorld init:

bool HelloWorld::init()
{

    if ( !CCLayer::init() )
    {
        return false;
    }

    CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
    CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
    addChild(CCLayerColor::create(ccc4(122, 144, 0, 255), visibleSize.width, visibleSize.height));

    //this is the layer that we want to "cut"
    CCLayer *layer = CCLayer::create();
    CCSprite* pSprite = CCSprite::create("HelloWorld.png");
    pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
    layer->addChild(pSprite, 0);

    //we need to create a ccnode, which will be a stencil for ccclipingnode, draw node is a good choice for that
    CCDrawNode * stecil = CCDrawNode::create();
    stecil->drawDot(ccp(visibleSize.width/2 + origin.x - 100, visibleSize.height/2 + origin.y), 30, ccc4f(0, 0, 0, 255));
    stecil->drawSegment(ccp(0, 0), ccp(visibleSize.width, visibleSize.height), 20, ccc4f(0, 0, 0, 255));

    //CCClipingNode show the intersection of stencil and theirs children
    CCClippingNode *cliper = CCClippingNode::create(stecil);
    //you want to hide intersection so we setInverted to true
    cliper->setInverted(true);
    cliper->addChild(layer);
    addChild(cliper);

    return true;
}
分类: stackoverflow精选, unity3d 标签:

How to smoothly move a button in cocos2d Xcode

2013年9月6日 没有评论

I have a jump button, that when clicked the player in game jumps. That button should be movable, how could I do that? I have seen the CCSprite moving images but don’t know how to do that with a button and I don’t have a UIViewController class, the scene is pushed by the CCDirector.

Also how could we zoom in and zoom out of scene a little bit to make it more featuring.

If the button is made by CCMenu, then you could use either actions or ccTouchesMoved method.

But if the button is made by UIButton, then you can use ccTouchesMoved and change the position of the UIButton based on where the user has dragged his finger across the screen.

My recommendation would be to create a HUDLayer, so everything I’m writing from now on will have this in regard.

The HUDLayer would be a CCLayer that is on top of the others, and fixed on the screen. In order for it to be on top, it needs to be added last or with the proper zOrder.

In this layer, you have to map the event ccTouchesBegan, and just work with the user’s touches. For instance, the character could jump when the user hits the right side of the screen. In order to do this, just see if CGRectContainsPoint(rightSideOfScreen, touchLocation), and if yes, make the character jump, and show the buttonSprite exactly on the touchLocation.

In order to hide the sprite, use ccTouchesEnded, so when the player will release the jump button, you could also hide the sprite.

分类: cocos2d, stackoverflow精选 标签: