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
优化方向主要有:引擎底层优化、纹理优化、渲染优化、资源缓存、内存优化。
引擎优化:
纹理优化:
纹理是最消耗内存的,而且会降低渲染速率,此部分是重点,下面会详细介绍。
渲染优化:
批次处理:使用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
相关文章推荐
- cocos2dx 3.10 移植到安卓步骤
- cocos2d-x 实现跨平台的目录遍历
- 【cocos2d-js官方文档】二十四、如何在android平台上使用js直接调用Java方法
- cocos2d-lua+cocos studio之ListView加载Item
- cocos2d-x-3.x snapshot
- cocos2dx 之 全局调度器
- cocos2dx3.10的TableView的实现
- 升级到cocos2d-x 3.10之后被遗忘的ccui.PageView.pageTurningEvent()
- cocos 一个描边shader
- cocos2dx的CCLabelTTF类使用不同的TTF字库时字体没有变化的问题
- cocos2d js v3.10 sprite点击事件的区域问题
- Cocos2d - Action学习总结
- Cocos 资料大全
- Cocos2d 植物大战僵尸游戏解析
- 编辑器CocoStudio和CocosBuilder的对比
- cocos工程打包apk,添加自定义C++类
- Cocos2dx - Scheduler学习理解
- 【Cocos Creator 实战教程(2)】——天天酷跑(动画、动作相关)
- Cocos2d-JS schedule用法
- Cocos2d-JS切换场景与切换特效