1、【资源释放的时机】
释放资源通常放在场景切换过程中,因为cocos2dx从场景A切换到场景B时,两个场景的生命周期是相互交叉重叠的,所以释放资源可以放在场景B的onEnterTransitionDidFinish生命周期里面,并且需要做适当的延迟,保证场景A已经被销毁后才能成功的释放场景A的资源。
2、【资源释放的最佳时机】
从场景A切换到场景B,中间添加一个Loading场景作为过渡,在Loading场景中,首先延迟一段时间,我习惯延迟2秒,然后进行一次资源释放。再延迟1秒,等待资源顺利被释放,然后开始加载场景B的资源,等场景B的资源加载结束之后再延迟1秒进入B场景。这时候由于缓存中只有场景B的资源和loading的资源,并且loadding的资源通常不大,所以卸不卸载也无所谓了。
3、【打印显存信息】
在资源释放后,我们可以打印下显存信息,代码如下:
CCTextureCache::sharedTextureCache()->dumpCachedTextureInfo();
可以显示纹理的名字,引用数,id,大小以及像素的bit值,最重要的是它展示了内存使用情况。
4、【资源释放的顺序】
由于纹理会被帧引用,所以释放的时候需要有个先后顺序:
骨骼动画缓存 --> 帧缓存 --> 纹理缓存。
释放骨骼动画资源缓存的代码如下(lua/需要用最新的player模拟器):
CCArmatureDataManager:sharedArmatureDataManager():purgeArmatureSystem()
5、【纹理优化】
5.1、尽量使用合图(plist + png),把纹理图的尺寸变成2的N次幂,但是不要做的太大,要避免大图。
5.2、尽量使用png压缩格式的图片。
5.3、cocos2dx默认在图片解压展开到显存的时候使用32位深度,我们可以降低图片展开的质量,使用16位甚至是8位深度。修改为16位深度的代码如下:
CCTexture2D::setDefaultAlphaPixelFormat(kCCTexture2DPixelFormat_RGBA4444);
6、【音频优化】
音频有三个因素影响文件内存使用,分别是音频文件格式,比特率,和样本率。
6.1、音频文件最好是mp3格式。因为它被android和ios都支持。而且它被压缩并且硬件加速了。其它格式的压缩率或许更高(如:ogg)对于缩减包大小有帮助,但是对于音频引擎解析速度是否有不良影响还未可知。
6.2、应该保证背景音乐文件大小在800KB以下。最简单的方式就是减少背景音乐播放时间并且重复调用。使用cocos2dx,有些限制还是要顾及的。
6.3、应该保持音频文件样本率在96-128kbps之间,并且比特率在44kHz就足够了。手机游戏不要要求太高。
6.4、android上打开音频后,流没有关闭。框架再unloadSound里面进行关闭处理,所以在需要卸载音频的时候调用sound.unloadAllSounds()就可以将load过的音频全部unload掉。缓存音频路径的table是GAME_ALL_EFFECTS,使用sound.preloadSound()预加载的音频没有缓存进去,需要手动释放或者手动添加到GAME_ALL_EFFECTS。【需要最新的bb.bin,早上刚让青山添加上去的API。】
7、【粒子系统】
粒子系统中,可以通过减少粒子数量来减少内存使用,也会降低渲染压力。对于很多非循环发射的粒子系统,在播放结束之后有的人就不管它了,其实该对象还是存在的,并且占用Draw Call,最好是粒子系统播放结束后手动进行移除。
8、【lua】
lua的变量使用结束后都要手动的置为空值(nil)。但是lua内存的回收时机是在C层面上决定的,并不及时,所以必要时可以手动调用collectgarbage("collect")进行一次显式内存回收。
显示lua虚拟机内存占用的代码如下:
collectgarbage("count")
9、【建议】
9.1、一帧帧的加载游戏资源,一次性加载的话会导致内存激增,可能会闪退,最好是加载完一张图,延迟几帧再加载下一张,我通常延迟0.2秒。
9.2、减少绘制调用。使用CCSpriteBatchNode。
9.3、按照最大到最小的顺序的加载纹理。
9.4、避开内存使用高峰,通常是场景创建的时候(一边销毁旧场景,一边创建新场景)。
9.5、使用加载界面来预加载游戏资源。
9.6、当不需要的时候释放无用的资源。
9.7、当有内存警告的时候释放缓存的资源。
9.8、使用texturePacker来优化纹理尺寸,格式,色彩深度值等等。
9.9、小心使用JPG文件。
9.10、使用16位RBGA4444色彩深度的纹理。
9.11、使用NPOT纹理代替POT纹理。
9.12、避开加载大尺寸图片。
9.13、使用1024*1024 NPOT pvr.ccz纹理图集而不是原生图片。
9.14、尽量少的使用luabinding中的方法,因为桥接到C++那边,性能差了不止一个档次。(例如:ccp(100, 100)我们可以用{x = 100, y = 100}的结构来替代,直到需要CCPoint类型的参数时,再构建ccp。)
9.15、尽量避免使用调度器、循环动作等。
9.16、box2D是个强大的物理仿真框架,但是性能不高,对于一些简单的物理效果,建议使用chipmunk,chipmunk在功能上虽然不及box2D强大,但是性能确实比较高。
9.17、对于一个场景中需要频繁创建、销毁的对象(比如:子弹),可以考虑使用对象缓存池,进行对象的回收和重用。关于对象缓存池可以参考cocos2dx 3.x版本的cc.Pool类。
9.18、使用短小的function和代码块,可以及时释放临时变量。
9.19、使用table.nums()方法来获取table的长度。避免在循环中使用“#”来获取table的长度。
9.20、避免使用“#tab == 0”这样的条件判断table是否是空表,应该使用“next(tab)”来判断。
【风险预估】
1、由于2.2的框架比较老旧,而且官方在2.x的引擎版本中为了无缝衔接cocos2d-iphone,留下了无数的坑,先天上肯定是有很多缺陷,无法和后续的cocos2dx版本相比较。所以对于一些资源量比较大或者明显需要占用较多内存的项目,要有一定的危机意识。
2、框架为了封装更加方便使用的API,某些方法内部进行了特殊处理,对性能有一定的影响。(越顶层的框架性能越低)
基于目前公司的框架和cocos2dx游戏引擎,客户端能做的优化途径
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
- 1 纹理基础 纹理是一种结构化的存储形式(Textures are a structured form of st...