14年中随着手游市场火热,我们决定进军手游。第一款游戏选择了我们所熟悉的仙侠类mmoarpg,毕竟这类型游戏我们积累了比较多的经验。在那个万众创业的时期,我们想招一个靠谱的cocos2dx主程并不容易。最终决定由我来负责客户端框架的设计,从此我从服务端转向了cocos2dx客户端。在经历了一个痛苦的过程之后,终于折腾出一个还算像样的框架。个中辛酸暂且不说,今天就谈谈资源处理的演变。
项目初始,在网上看到很多人推荐图片使用pvr4444格式,用TexturePacker把图片合成一个大图加plist的形式。cocos2dx提供了通过plist文件加载图集的接口,哈,使用起来没有一点难度嘛。然后我叫阿华写了个脚本,用于打包图集。阿华是个很博学的人,就像一本活字典,几乎什么计算机的问题都可以问他,很快他就把脚本搞好了。考虑到图片文件的加载会比较耗时,所有动画都使用异步加载。TextureCache有提供异步加载纹理的接口addImageAsync,本着不重复造轮子的精神,尽量使用引擎有提供的功能。然而这个接口有个bug,我在 http://blog.csdn.net/xiewuquan/article/details/50493490这篇文章里有提到,并且修正了。当时为了让代码写起来比较简单方便,我做了一个错误的决定,UI使用同步的方式创建。为了使UI打开更顺畅,几乎所有UI都是不销毁的,创建出来之后就常驻内存,这给我以后的内存优化带来了很大的麻烦。
使用一段时间之后有了新的问题:1、资源过多,需要想办法缩小资源大小;2、有些图片质量较差,看起来不够美观;3、游戏运行不够流畅,有卡顿现象。经询问朋友,了解到他们图片使用png格式,使用pngquant将图片压缩为8位的,图片质量比pvr4444要好,文件大小也更小,部分需要更高画质的使用png32位的。问题1、2暂时得以解决。对于问题3,我在debug模式下测试发现,plist文件的加载、解析占用的时间接近png文件的加载,当时觉得很不可思议。既然这么慢,那只好换了它。首先拿UI资源的plist开刀,我们使用的是cocos2dx+lua的模式开发,我就想把plist转成lua,通过require加载进来,然后自己创建精灵帧,lua的require效率确实相当的高。然而动画的加载是在C++实现的,这部分暂时没改。过了一段时间我又想干嘛不直接转成自定义的格式,自己解析。然后我把脚本改了一下,把plist的格式改成了自己定义的文本,使用C函数去解析,这时针对plist的加载解析时间基本可以忽略了。
这种方式一直持续到游戏上线,后续的开发不时会添加资源,包体越来越大,我们需要更小的包,方便推广。我在lua里写了一些动态下载的逻辑,然后打包时可以删除部分资源。这个项目及后一个换皮项目,基本都是这种模式。虽然有许多不完美,但是这两个项目还是创造了不错的成绩,特别是第二个项目,2016年1月,月流水已达3千万。
新项目的优化:
图集使用了两种格式的配置,下载一个动画时一次要下两个文件,并且下载的逻辑比较复杂,这些都让我不舒服。我抛弃了TextureCache的异步接口,重新设计了一个资源管理类,把图片文件和图集配置合并成一个文件,异步加载的接口支持自动下载,逻辑代码在使用的时候可以不用考虑动画资源是否存在,像正常一样使用,资源不存在会自动下载,并且可以自动卸载资源,避免长时间不使用的资源占用过多内存,也可以手动卸载。重新实现了帧动画,效率更高,接口更友好。修改了UI的创建方式,使UI创建更为平滑,UI关闭时超时销毁。
另外还有地图资源,我们一般用的是几千乘几千像素的大场景,这么大的图肯定不可能一次性加载整张地图。我们把它切成512*512的图块,图块使用jpg格式,在清晰度和资源大小上选择了一个合适的压缩比例。cocos2dx内存里默认使用RGBA8888格式,而jpg图并不需要透明通道,我修改了一下引擎代码,使其在内存里使用RGB888格式,减少内存占用。
至此经历了以下几个主要阶段:
1、pvr4444 + plist
2、png + plist
3、png + plist, png + lua并存
4、png + txt, png + lua并存
5、png与txt合并成自定义格式
资源动态下载从lua逻辑层实现变成C++底层实现,上层逻辑可以不关注资源的下载
项目初始,在网上看到很多人推荐图片使用pvr4444格式,用TexturePacker把图片合成一个大图加plist的形式。cocos2dx提供了通过plist文件加载图集的接口,哈,使用起来没有一点难度嘛。然后我叫阿华写了个脚本,用于打包图集。阿华是个很博学的人,就像一本活字典,几乎什么计算机的问题都可以问他,很快他就把脚本搞好了。考虑到图片文件的加载会比较耗时,所有动画都使用异步加载。TextureCache有提供异步加载纹理的接口addImageAsync,本着不重复造轮子的精神,尽量使用引擎有提供的功能。然而这个接口有个bug,我在 http://blog.csdn.net/xiewuquan/article/details/50493490这篇文章里有提到,并且修正了。当时为了让代码写起来比较简单方便,我做了一个错误的决定,UI使用同步的方式创建。为了使UI打开更顺畅,几乎所有UI都是不销毁的,创建出来之后就常驻内存,这给我以后的内存优化带来了很大的麻烦。
使用一段时间之后有了新的问题:1、资源过多,需要想办法缩小资源大小;2、有些图片质量较差,看起来不够美观;3、游戏运行不够流畅,有卡顿现象。经询问朋友,了解到他们图片使用png格式,使用pngquant将图片压缩为8位的,图片质量比pvr4444要好,文件大小也更小,部分需要更高画质的使用png32位的。问题1、2暂时得以解决。对于问题3,我在debug模式下测试发现,plist文件的加载、解析占用的时间接近png文件的加载,当时觉得很不可思议。既然这么慢,那只好换了它。首先拿UI资源的plist开刀,我们使用的是cocos2dx+lua的模式开发,我就想把plist转成lua,通过require加载进来,然后自己创建精灵帧,lua的require效率确实相当的高。然而动画的加载是在C++实现的,这部分暂时没改。过了一段时间我又想干嘛不直接转成自定义的格式,自己解析。然后我把脚本改了一下,把plist的格式改成了自己定义的文本,使用C函数去解析,这时针对plist的加载解析时间基本可以忽略了。
这种方式一直持续到游戏上线,后续的开发不时会添加资源,包体越来越大,我们需要更小的包,方便推广。我在lua里写了一些动态下载的逻辑,然后打包时可以删除部分资源。这个项目及后一个换皮项目,基本都是这种模式。虽然有许多不完美,但是这两个项目还是创造了不错的成绩,特别是第二个项目,2016年1月,月流水已达3千万。
新项目的优化:
图集使用了两种格式的配置,下载一个动画时一次要下两个文件,并且下载的逻辑比较复杂,这些都让我不舒服。我抛弃了TextureCache的异步接口,重新设计了一个资源管理类,把图片文件和图集配置合并成一个文件,异步加载的接口支持自动下载,逻辑代码在使用的时候可以不用考虑动画资源是否存在,像正常一样使用,资源不存在会自动下载,并且可以自动卸载资源,避免长时间不使用的资源占用过多内存,也可以手动卸载。重新实现了帧动画,效率更高,接口更友好。修改了UI的创建方式,使UI创建更为平滑,UI关闭时超时销毁。
另外还有地图资源,我们一般用的是几千乘几千像素的大场景,这么大的图肯定不可能一次性加载整张地图。我们把它切成512*512的图块,图块使用jpg格式,在清晰度和资源大小上选择了一个合适的压缩比例。cocos2dx内存里默认使用RGBA8888格式,而jpg图并不需要透明通道,我修改了一下引擎代码,使其在内存里使用RGB888格式,减少内存占用。
至此经历了以下几个主要阶段:
1、pvr4444 + plist
2、png + plist
3、png + plist, png + lua并存
4、png + txt, png + lua并存
5、png与txt合并成自定义格式
资源动态下载从lua逻辑层实现变成C++底层实现,上层逻辑可以不关注资源的下载
jpg图在内存的格式从RGBA8888变成RGB888,减少jpg图的内存占用,并且加快加载速度。