本次教程主要讲解下spritesheet(精灵图表,主要用的是CCSpriteBatchNode)的优点和怎么用spritesheet来创建一个动画。
本次教程的参考文章有:himi的博客文章关于CCSpriteBatchNode的, http://blog.csdn.net/xiaominghimi/article/details/6761811
子龙山人的翻译文章:http://www.cnblogs.com/zilongshanren/archive/2011/04/11/2012770.html
如果你对cocos2d-x编程不了解,可以先阅读《用cocos2d-x做一个简单的windows phone 7游戏》系列文章。不过,如果你有相关的经验就另当别论了。
如果你从来没有使用过spritesheet,你可以把它看作是一张巨大的图片,你可以把许许多多的sprite放进去。与spritesheet对应的,还有一个plist文件,这个文件指定了每个独立的sprite在这张“大图”里面的位置和大小,当你在代码之间需要使用这个sprite的时候,就可以很方面地使用plist文件中的这些信息来获取sprite。
使用CCSpriteBatchNode来获取spritesheet里面的精灵可以提高效率。
为什么这会提高效率呢?因为cocos2d-x对它进行了优化!如果你使用spritesheet来获取sprite,那么当场景中有许多sprite的时候,如果这些sprite共享一个spritesheet,虽然在XNA里面没有OpenGL ES,不过渲染方式也差不多,以 XNA 为基础的游戏可以在呼叫 spriteBatch 物件的 Begin 方法和呼叫 spriteBatch 物件的 End 方法之间执行多个绘制图形和文字的文字,由 XNA Framework 以批次的方式一次显示多個图形內容。那么cocos2d-x就会使用一次spriteBatch呼叫来绘制这些sprite。但是,如果是单个的sprite的话,那么就会有N次spriteBatch呼叫,这个代价是相当昂贵的。其优化也不过在于减少了对spriteBatch的Begin和End方法的调用。
简而言之--使用spritesheet会更快,尤其是当你有很多的sprite的时候!
Zwoptex To Victory!
虽说plist就是一个文件, 但是手动用图片编辑器编辑图片后再编辑plist文件也是相当麻烦的事情,这里用到一个免费的工具,Zwoptex.我用的是flash版,安装版是收费版的。毕竟我们就是编辑个图片,flash版就够了。
先下载这次教程需要的图片,用的图片是子龙山人翻译的文章原作者ray的图片,熊行走的图片(用这图片,主要是找图片困难,而且最主要的原因,我的画图水平真的很菜,PS就是在会用的水平,哎,没有美工的日子)
下面下载Zwoptex,http://zwopple.com/zwoptex/static/downloads/zwoptex-flashversion.zip,这个链接还真是在网站上有点难找,所以直接贴出链接。下载完毕,然后解压后打开Zwoptex.html。
然后可以开始创建spritesheet了。点击File/import images,把所有的bear图片8张全部选中,然后点击打开加入到工程中,你会发现所有图片都重叠在一块了。我们现在并不需要这么大的图片,点击Modify/Canvas width,选中512px,这么大就够了,然后点击Array/by Name &Height,这时发现熊是每两个一排,总共4排,这时,对图片的编辑就算是完了。然后就导出吧。点击File/Export Texture.保存为AnimBear.png。然后继续点击File/Export coordinates。保存为AnimBear.plist.
让熊动起来吧
现在打开VS2010,新建一个cocos2d-x的工程,命名为cocos2dBearRunDemo,同样的,OpenXLIve插件不用。和以前的工程一样,修复DLL引用是必须的。由于这次示例比较简单,所以直接在HelloWorldScene里面修改了。那么就把HelloworldScene里面的init方法清理下吧。
在Content工程里面新建一个resource文件夹,并且在resource文件夹里面新建一个images文件夹,并且把AnimBear.png添加到resource/images里面,AnimBear.plist添加到resource文件夹内。然后在解决方案管理器里面选择AnimBear.plist文件。选择属性。然后修改ContentImporter和ContentProcessor,如下:
如果你的不能出现这两个选项,敬请查看Content的引用,确认cocos2d.Content.Pipeline.Importers的引用没有显示为叹号。如果有,移除后重新添加。
然后直接打开AnimBear.plist文件。删除下面红色框的那行后保存。
为什么要删除这么一行呢,因为XNA版的cocos2d-x是用XML的解析方法,这行不能跳过,会报错。所以,直接删除即可。
现在,打开HelloWorldScene文件。开始真正的动画制作。下面都是在Init里面修改.
为了获得动画效果,我们有5个步骤需要做。接下,将会一个步骤一个步骤给大家讲解。
1) 缓冲sprite帧和纹理
CCSpriteFrameCache.sharedSpriteFrameCache().addSpriteFramesWithFile(@"resource/AnimBear");
首先,调用CCSpriteFrameCache的addSpriteFramesWithFile方法,然后把Zwoptex生成的plist文件当作参数传进去。这个方法做了以下几件事:
- 寻找工程目录下面和输入的参数名字一样,但是后缀是.png的图片文件。然后把这个文件加入到共享的CCTextureCache中。(这我们这个例子中,就是加载AnimBear.png,由于XNA工程的AssetName的问题,两个一样名字的文件会发生冲突(这个与文件后缀无关),所以把AnimBear.png文件放在了下一级目录中。)
- 解析plist文件,追踪所有的sprite在spritesheet中的位置,内部使用CCSpriteFrame对象来追踪这些信息。
2) 创建一个精灵批处理结点
CCSpriteBatchNode spritesheet = CCSpriteBatchNode.batchNodeWithFile(@"resource/images/AnimBear"); this.addChild(spritesheet);
接下来,创建CCSpriteBatchNode对象,把spritesheet当作参数传进去。spritesheet在cocos2d中的工作原理如下:
- 你创建一个CCSpriteBatchNode对象,通过传递一个包含所有sprite的spritesheet的名字作为参数,并把它加入到当前场景之中。
- 接下来,你从spritesheet中创建的任何sprite,你应该把它当作CCSpriteBatchNode的一个孩子加进去。只要sprite包含在spritesheet中,那么就没问题,否则会出错。
- CCSpriteBatchNode可以智能地遍历它的所有的孩子结点,并通过一次spriteBatch的呼叫来渲染这些孩子,而不是以前每个sprite都需要一个spriteBatch呼叫,这样渲染速度就会更快。
3) 收集帧列表
List<CCSpriteFrame> walkAnimFrames = new List<CCSpriteFrame>(); for (int i = 1; i <= 8; i++) { walkAnimFrames.Add(CCSpriteFrameCache.sharedSpriteFrameCache().spriteFrameByName(String.Format("bear{0}.png", i))); }
为了创建一系列的动画帧,我们简单地遍历我们的图片名字(它们是按照Bear1.png-->Bear8.png的方式命名的),然后使用共享的CCSpriteFrameCache来获得每一个动画帧。记住,它们已经在缓存里了,因为我们前面调用了addSpriteFramesWithFile方法。
4) 创建动画对象
CCAnimation animation = CCAnimation.animationWithFrames(walkAnimFrames, 0.1f);
接下来,我们通过传入sprite帧列表来创建一个CCAnimation对象,并且指定动画播放的速度。我们使用0.1来指定每个动画帧之间的时间间隔。
5) 创建sprite并且让它run动画action
CCSize winSize = CCDirector.sharedDirector().getWinSize();
CCSprite bear = CCSprite.spriteWithSpriteFrameName(@"bear1.png"); bear.position = new CCPoint(winSize.width / 2, winSize.height / 2); var walkAction = CCRepeatForever.actionWithAction(CCAnimate.actionWithAnimation(animation, false)); bear.runAction(walkAction); spritesheet.addChild(bear);
我们首先通过spriteframe来创建一个sprite,并把它放在屏幕中间。然后,生成CCAnimationAction,并赋值给场景的walkAction属性,最后让熊来运行这个action。
最后,我们把熊加个场景中--把它当作spritesheet的孩子加到spritesheet中去。注意,如果在这里我们没有把它加到spritsheet中,而是加到当前层里面的话。那么我们将得不到spritesheet为我们带来的性能提升!!!
完成了!
另外,由于我们只有一个场景,要添加一个label才能使sprite的背景透明,这个暂时不清楚是什么原因。那么就添加一个吧。
CCLabelTTF label = CCLabelTTF.labelWithString("Bear walk", "Arial", 32); label.position = new CCPoint(winSize.width / 2, winSize.height - 80); this.addChild(label);
现在运行,就能看到熊在走了。
那么怎么让熊转向呢,设置熊的属性bear.IsFlipX = true;也就是X轴翻转。就能使熊翻转过来了。当然,也能竖直翻转。
另外摘抄些注意事项:
使用CCSpriteBathNode虽然能达到优化,但是要注意一点:
初始化精灵集合CCSpriteBatchNode的时候会加载一张图片资源(或者pvr文件等),那么限制其精灵集合的子精灵都必须使用集合加载的这张图才行,否则会给出警告;
使用CCSpriteBatchNode还要注意一点,因为精灵都存放在集合中,那么这个集合CCSpriteBatchNode中的节点(精灵)都将在同一个z轴上,同一深度上;
本次教程就到此结束了。示例代码下载:http://dl.dbank.com/c04ey6mse6