您的位置:首页 > 移动开发 > Cocos引擎

cocos 优化方案

2016-05-04 14:20 337 查看
Cocos2d-x优化方案
优化方向主要有:引擎底层优化、纹理优化、渲染优化、资源缓存、内存优化。

引擎优化:

纹理优化:

纹理是最消耗内存的,而且会降低渲染速率,此部分是重点,下面会详细介绍。

渲染优化:

批次处理:使用CCSpriteBatchNode,准备好Sprite的坐标信息后,进行一次性渲染。

传统渲染处理:不同的切换纹理,不同地加载和渲染。

二者区别:批次处理是一次加载完所有纹理,然后一次渲染,从而提高渲染效率。

资源缓存:

CCSpriteFrameCache和CCTextureCache

缓存比较耗电量,所以一般使用完后要调用remove函数移除缓存,而且在预加载时要显示进度条,可能会影响用户体验,应该根据情况使用。

内存优化:

资源占用的内存优化,如前面几个小节所述。

内存池方案:

游戏启动的时候就分配很大的一块区域,游戏运行过程中不释放,直到退出游戏再释放。平时不是为新资源分配内存,而是把资源加载到内存池里面。多次使用的时候,就不用经过多次的释放和重新加载。这部分可以多了解下C++的内存池管理机制。

优化方案详解

纹理优化:

1. 合成优化:

OpenGL在申请内存存放纹理时,是按2的幂次方申请的,即对应480*320的图片,它申请的是512*512空间。可见,会有相当多的内存被浪费。所以,我们设计的图片,最好是2的幂次方,不然OpenGL最终还是申请2的幂次方内存空间。

由于不是所有图片都刚好能设计成2的幂次方,因此通过“拼图”方法解决,即使用TexturePacker将小图合成大图。

2. 色深优化:

图片所占内存的大小用这条公式计算:高度像素*宽度像素*色深。

如色深RGBA8888,是32个bit,每8bit是一个字节,因此一个像素点占4字节,就是一个整形字符大小。例子,一个480*320的图片大小,占内存480*320*4字节。

通常,如果对图片的色彩要求不是很高的话。ARGB8888(占4字节)可以改为,ARGB1555(2字节)(透明通道A占1位一般是用做图片混合运算)或者ARGB4444(如果不是做混合运算,用4位比较合适)。或者,如果不需要使用图片透明,就不需要A通道,直接使用RGB888(3字节)改为RGB565(2字节)。这样,图片的最终内存大小就会占用更少的空间。

1. 格式优化:

IOS系统使用PowerVR显示芯片,可以直接硬解码PVR格式,该格式可以直接被IOS读取。不过该方式不适合Android等平台。PVR格式实际上就是把ARGB8888转成ARGB1555色深进行保存的。

2. 尺寸优化:

不同设备支持的纹理尺寸不一样,iphone4支持最大的是4096*4096,iphone4s是4096*2048。有的android设备,仅仅限制在1024*1024。拼图的时候要避免把图片拼的太大。为了提高游戏的兼容性,图片的尺寸最好都设置在1024*1024范围内(主流设备都支持)。

渲染优化:

在合计内存时,不仅仅只计算加载到缓存中的内存。以一张1024*1024的图片为例,

CCSprite *pSprite = CCSprite::spriteWithFile("a.png");

使用上边这行代码之后,可以在LEAKS中看到增多了大概4M的内存。而后接着调用

addChild(pSprite);

这时,内存又增加了4M。也就是说,一张图片,若是被渲染的话,那它所占用的内存将要X2。

再看看经过plist加载的图片,例如这张大图尺寸为2048*2048,想要加载其中一张32*32的小图片

CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("b.plist");

此时内存增加16M,

CCSprite *pSpriteFrame = CCSprite::spriteWithSpriteFrameName("b1.png");

b.png 大小为32*32,主观上会认为只是增加了一点点内存,可实践证明是增长16M内存。也就是只有渲染了大图中的一局部,那么整张大图都会被一起加载。

但是情况并不是那么的糟糕,这些曾经渲染的图片,假定再次加载的话,内存是不会再持续增长的,比方又添加了100个b.plist的另一个区域,图片内存照旧为16+16
= 32M,而不会继续上升。

资源缓存:

Cocos2d-x 在使用spriteWithFile或者spriteWithSpriteFrameName等创建精灵时,cocos2d-x都会将这张图片加载到缓存中。若是是第一次加载这个图片,那就会先将这张图片加载到缓存,往后从缓存读取。假如缓存中已经存在,则直接从缓存中提取,免去了加载进程。

Cocos2d-x图片缓存主要用到cache机制类,这些类都是单例类的管理器。

CCSpriteFrameCache(精灵帧) ,CCTextureCache (纹理)

CCSpriteFrameCache加载的是一张拼接过的大图,每个小图只不过大图中的一个区域,这些区域信息都保存在plist文件中。用的时根据小图的名称便可以加载这个区域。

CCTextureCache 是普通的图片缓存,我们所有直接加载的图片都会默许放到这个缓存中,

因而,每次加载一张图片,或者使用plist加载一张拼接图时,都会将整张图片加载到内存中。

注意:这些cache类内部也使用了ratain和release方法,防止这些资源被释放掉。

我们可以使用这些cache保存预加载的一些资源,方便调用和内存优化。但是这些cache在场景切换时,不会自动删除,需要手动调用purgeXXXX方法,进行清理。

缓存释放:

假定游戏有不少场景,在切换场景的时可以把前一个场景的不再使用的内存释放,预防总内存过高。

CCTextureCache::sharedTextureCache()->removeAllTextures();
释放所有加载的图片。

CCTextureCache::sharedTextureCache()->removeUnusedTextures();
将引用计数为1的图片释放CCTextureCache::sharedTextureCache()->removeTexture();单独释放某个图片

值得注意的是,场景切换在不同的情况下所调用的函数顺序不同,

假定从A场景切换到B场景,则函数调用的顺序为:

B::init()---->A::exit()---->B::onEnter()

假定使用了切换效果,譬如CTransitionJumpZoom::transitionWithDuration这样的函数,则函数的顺序为:

B::init()---->B::onEnter()---->A::exit()

使用第二种方式会有一刹时将两个场景的内存叠加在一起,若是不及时且得当地处理,很可能会由于内存短促增高而使程序被系统杀死。

内存优化:

优化的心得等于只管去拼接图片,尽量将小图片拼接在2的N次方的大图中。但需要注意的是,将逻辑相关的图片打包在一张大图里,将逻辑不相关的图片做另外处理,而不是一味的只将小图片都打包在大图中。由于渲染顺序可能会用到CCSpriteBatchNode;对应单个BatchNode里的图片凡是位于一个层级的,必须根据各个图片的层级关系,打包到不同的plist

里。否则内存与顺序不匹配,可能造成内存管理失调。

总结:

1、图片占用内存的是它的像素格式和大小,与其扩展名无关。只要图片像素格式都是argb8888,那么最终图片占用的内存是一样的。

2、如果不是pvrtc4的格式,那么不要扩展成2的整次幂,因为图片越小,占用内存越小

3、单单去除透明通道不会减少图片所消耗的内存,png和jpg图片也无法减少图片体积,所以不推荐rgb888的格式。替代选择rgb565和rgb5551。

4、加载图片时临时开辟的纹理数据造成的内存飙高,可以考虑加入内存池,及时的开辟和释放缓冲区。

5、如果是为了减少图片体积可以选择:

(1)jpg--压缩比最高,质量较好,但是不支持半透明

(2)png8--同样图片会比jpg略大一些,使用ImageAlpha进行转换,视觉上几乎看不出差别。 这两种图片格式都可以极大的减少图片体积(减少70%~80%),但是无助于减少内存

6、如果是为了减少内存可以选择:

(1)没有透明色的图片统一转换为rgb565格式,这个时候无法使用png8了,所以png和pvr.ccz图片大小几乎相同,pvr.ccz速度更快,所以推荐pvr.ccz的rgb565格式

(2)如果透明色仅仅是进行关键色标注,而没有渐变混合,那么推荐rgb5551 (r5_a1)的pvr.ccz格式

交流群: 422209275
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: