缘由
在游戏开发中,通常对于性能的处理
是比应用型的App
要敏感一些.游戏中的操作往往比较频繁
而且多数都需要立刻响应
,若是性能问题
导致用户体验卡顿
,算是比较糟糕
的情况了,对于大型游戏
开发公司来说,会有专门的团队(也可能是个人)
处理性能优化,其重要性不言而喻
.在cocos2d
的项目开发中,性能调节
的入手点往往都是最先由纹理
开始的.下面我们就来讲一下纹理的基础知识
.
什么是纹理(Texture)?
纹理,我们可以认为是cocos2d
中需要在屏幕上显示
的所有节点(CCNode)
的样子,可以把它理解为外貌
,有时候也常常被称为皮肤
,也就是显示在我们眼前的形状,颜色
的统称.
纹理(Texture)也是图像绘制
里的专用语,就是指将要显示的目标
绘制成何种样子
.换句话说就是图像绘制系统
会根据纹理的数据
来在屏幕上绘制
目标元素.在cocos2d中,图像绘制系统
就是openGL
,纹理(Texture)通常是我们项目中的图片资源
,因此我们也会在开发中经常说纹理图片
.
例如我们在项目中
会这样显示一个图片
在屏幕上:
CCSprite *userHeadSprite = [CCSprite spriteWithImageNamed:@"xxxx.png"];
[self addChild:userHeadSprite];
实际上图片(xxxx.png)
是先被加载到纹理缓存
中,在显示的时候由openGL
将图片纹理
绘制到屏幕上,这样
我们就可以看到这个图片
了.
纹理的渲染
在cocos2d
中的图形处理
是使用的openGL
技术实现的,因此它对需要绘制的图片
有一些特殊的要求
: 图片的长和宽
必须是2的整数幂
,基于这样的一个规定,我们如果需要显示一个17x17
的图片时,实际上需要一个32x32
的绘制纹理
才可以装得下这个图片
,造成内存的额外开销
和浪费存储空间.也正是由于这个纹理渲染
的原因,我们才需要对纹理
进行一些适当的
处理,以合理
的减少不必要
的浪费.
openGL
绘制纹理过程十分复杂
,去除其中的细节(说的好像自己知道似的^_^)
可以笼统的
概括为三个步骤:
-
- 绘制纹理的准备(预处理) :
开启绘图缓冲
- 绘制纹理的准备(预处理) :
- 2.纹理绘制:
绘制缓冲的内容
-
- 绘制纹理的结束(收尾):
关闭绘制缓冲
- 绘制纹理的结束(收尾):
项目开发
中肯定会有很多的图片资源
需要展示
到屏幕上,如果每个图片资源
都执行上面的绘制步骤
,除了耗费很多不必要的绘制资源
之外,还进行了很多重复性的操作
.频繁的开启和关闭绘制缓冲
也是导致性能下降
的一个重要因素
,为了尽量避免
这种情况,我们需要将一个一个
单独的图片资源
,合并为一张图片
,然后使用合并后的图片
进行一次纹理渲染
就可以了.这样既减少了重复的绘制操作
,也合理的利用了内存空间
,那么接下来的问题是:如何将许多原本单独的图片
组合为一个通用的图片资源
呢?
答案是: 打包
如何打包?
游戏开发
中会用到很多代码之外
的工具,纹理打包
有很多工具软件,笔者使用的TexturePacker
,关于这个软件简单使用可以看图例,详尽的
使用方法大家可以自行百度
在TexturePacker中设置好参数之后,点击
Publish sprite sheet
就可以完成打包并导出
最后会
在你指定的
文件夹路径下会生成两个文件:一个plist文件
,一个png文件
使用打包后的纹理
图片资源
经过纹理打包
之后,我们就可以把它们导入
到项目中并准备使用
.如果你的项目是cocos2d
的新版本(笔者的版本为cocos2d-3.5)
,那么恭喜你,加载纹理打包后的文件(plist文件)
只需要一行代码
即可,其他地方都不要修改.
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"TexturePacker导出的plist文件.plist"];
如果你的项目使用的cocos2d
是比较早的版本(3.0之前)
,除了上面的代码之外,你需要这样使用
加载后的纹理资源
:
// 图片名称可以从纹理打包的plist文件里查看
CCSpriteFrame *spriteFrame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"你需要的图片名称.png"];
CCSprite *sprite = [CCSprite spriteWithSpriteFrame:spriteFrame];
使用打包后的纹理资源
(通常都是一张图片),cocos2d
会将纹理资源
一次渲染完成,提高了图片资源
的加载和使用效率
.
被遗弃的CCSpriteBatchNode
还记得前面提到的纹理渲染
的三个步骤么(准备,绘制,收尾)
?,在cocos2d-3.1
之前, 每个CCSprite
在被绘制(draw)
到屏幕上时,都会执行这三个步骤!
如果你的项目属于cocos2d- 2.x
版本的,推荐你使用CCSpriteBatchNode
类来优化渲染. CCSpriteBatchNode
可以将多个CCSprite
添加到渲染队列
中去,然后只需要提交一次渲染操作
就可以将需要绘制的CCSprite
一次全部绘制完成
.
CCSpriteBatchNode *batchNode = [CCSpriteBatchNode node];
CCSprite *s1 = [CCSprite spriteWithImageNamed:@"s1.png"];
// ..... 设置s1的其他代码...
CCSprite *s2 = [CCSprite spriteWithImageNamed:@"s2.png"];
// ..... 设置s2的其他代码...
CCSprite *s3 = [CCSprite spriteWithImageNamed:@"s3.png"];
// ..... 设置s3的其他代码...
[batchNode addChild:s1];
[batchNode addChild:s2];
[batchNode addChild:s3];
[self addChild:batchNode];
cocos2d- 3.1+之后,CCSpriteBatchNode
已被标记为废弃,这是因为CCNode
默认会帮助我们完成一次性将多个CCSprite(精灵)
的渲染工作,不再需要专门使用CCSpriteBatchNode
来手动实现了.
尽管在最新的cocos2d
版本中依然保留了CCSpriteBatchNode
,但你基本上都不会怎么用到它了.
结束语
cocos2d 3.0+
新版本为我们提供很多便利性
的功能,也正是由于这样会导致和之前的旧版本
有一些比较明显的差异
,希望在使用中的朋友们
能够留意
这里面的一些变化,并通过对比来理解
其中的原因,对于项目开发也是十分有益处的
.