贴图优化
贴图资源是游戏当中消耗最大的资源,贴图资源的管理直接影响到整个游戏内存的性能。
- 使用图集:使用图集能够很好解决drawcall过高的问题。Unity中的SpritePacket能够很好地帮助我们建立图集,而且支持剥离透明通道,帮助我们更好地压缩图集文件,减少资源内存的占用。在雨松MOMO的博客当中对其也有比较详细的讲解:UGUI研究院之SpritePacker打包参数(四)
- 对于通用纹理,尽可能的使用九宫格。如果用大块的纹理则会占用较大的内存空间。而针对对称纹理则可以使用shader或者Scale翻转等方法来重复利用以减小内存消耗。
- 对于有较明显的远近关系的物体,我们可以使用Mipmap来减少运行时渲染的带宽。如果没有这种需要的话(例如2D场景和UI)则需要及时关闭,因为会占用一定的内存空间。Unity中也有Mipmap视图提供给我们进行查看:
- 通过设置“MaxSize”来限制图片的大小,一般来说我们应该讲图片缩小到肉眼刚好看不出压缩的程度。图片不要超过2048.
- “Format”则表示压缩的方式,不同的平台我们应该用不同的压缩方式来进行压缩。例如:安卓使用ETC而IOS则使用PVRTC。
- 一般情况下我们需要关闭图片的Read&Write选项,否则内存会大一倍。除非我们对图像需要进行读写操作。
- 针对颜色范围不大的素材,我们可以降低图片的色阶以减小图片的大小。
模型优化
- 保证不可读写。
- 将没有动画的模型上的动画脚本去除,否则会消耗cpu。
- 多个角色分享一套rig,可以解决资源。
- 使用MeshCompression
- 模型莫名期末有很多particle view*物体。在3DMAX中当你按下6时候,会弹出particle view窗口。同时会生成一个多余的particle view物体(这个物体在大纲中是找不到的,但当使用Ctrl+A的时候,他就会被选到,而且这个物体会占用一定的文件空间),在导出时particle view会严重扰乱物体的轴心。决方法很简单,只要在max导出之前,按下f11键,进入max的脚本编辑器,输入delete $’particle view*’,回车,此时下一行会提示有几个particle view被删除了。看到这个数字即可以放心导出了。
- 当动画播放出现褶皱、破损、奇葩的时候,估计是点受骨骼影响太多了,U3D设置中一个点最多只能受4个骨骼影响。
- 在UI中最好不要使用Mesh特效,否则无法判断深度。除非使用RendererTexture来适应,尽可能让美术用别的方案来替代。
音频优化
- 在IOS上使用Mp3 Compression,而在安卓上使用Vorbis Compression
- 在移动游戏中使用Force Mono
- 比特率调的尽可能低
文本文件优化
- 解析文本是比较慢的。
- 将文本转成二进制文件,可以有效提高读写速度。
- 将文本分成小块,只读取需要的部分。读入之后如有必要则Cache起来。
- 利用线程进行多线程读取。
AssetBundle管理
目前市面上的大多数游戏都要涉及到热更新,从Unity5.0开始,简化的API让AssetBundle的打包似乎不再是一件困难的工作,但是想要管理好AssetBundle的关系却并不是那么容易的一件事。
在游戏中加载资源我使用过两种做法,都需要自己对加载方式进行封装,通过多态来灵活加载工程内或者热更的资源:
- 一种是讲所有需要加载的资源,例如prefab、文本等等放入到Resources下面(尽可能减少资源否则会影响启动速度),而依赖的资源放在别的文件夹下,热更的时候将资源加载到沙盒目录下。在资源加载的时候,首先对沙盒目录进行检查,若有的话,则使用热更资源,否则就加载Resource下的资源。优点是在工程内不需要打包,而缺点是由于没有打包,导致在最后出包的时候打包缓慢。
- 而另一种是将所有的资源打成AssetBundle放入StreamingAssets下,热更的时候同样十八AssetBundle下载到沙盒目录下。资源加载的时候,首先对沙盒目录进行检查,若有的话使用热更资源,否则就加载StreamingAssets下的资源。在加载的时候需要提供资源名和包名,在编辑器下可以通过AssetDatabase来直接从编辑器中加载资源,通过将场景加入到BuildSetting中来加载场景,避免每次进行修改的时候都需要重新打AssetBundle。这种方法在最后出包的时候比较快,在最终确定下资源正确性的时候构建AssetBundle。
- 通过延迟加载来对AssetBundle进行加载,在一般的使用场景下,我们并不需要将所有的AssetBundle进行载入。在游戏中,我们将建立一张常用的Bundle列表,用于进入场景时加载该场景中的常驻资源。而不一定会出现的资源则在需要的时候进行即时加载,并且放入Bundle池中随时准备取用,当Bundle闲置达到一定的时间后对其进行自动的卸载,这取决于该Bundle的使用频度。在切换场景之后卸载该场景的常用Bundle而去加载另一个场景的常用Bundle。
- 要注意Bundle的细粒度,如果Bundle的细粒度超过一定数量的话必然会引起热更包体积过大,玩家的更新需要下载更多的资源包,而在场景中也需要加载更多原本并不被需要的资源,而过小细粒度则会造成场景加载的缓慢,给管理上也会增加难度。所以适当的细粒度在AssetBundle的分包中也非常重要。
- 将公用的资源单独打成包:如果一个资源本身没有标记任何的Bundle包,而被许多别的Bundle包引用则会被打入每一个引用它的Bundle中,造成包体积的膨胀。例如Shader这样的材质就很有必要单独打成一个包用作公用,否则包体积和游戏内存占用会变成一个大问题。
- 当手机的容量较小时,可以通过WWW.LoadFromCacheOrDownload来进行加载,而不必担心内存不足的问题。
- 在将代码打包到Prefab的时候对于Component要用动态加载的方式,考虑使用lua脚本进行操作,或者是直接动态从程序集加载,这样可以避免资源与代码不同步的情况发生。可以只对代码进行修改而不需要重新进行资源打包。
- 在使用第二种方案建立项目的时候可以建立一个或者几个资源项目,用于大量资源的打包,用于将AssetBundle打包并放入主项目中,在主项目的在打包的时候不必再对所有的AssetBundle资源进行再打包,可以大大提高打包效率,并且可以将工作流放入到资源项目当中,提高资源的迭代效率。
- 在为资源分包的时候可以按照文件夹来进行区分,以便于管理。
- 当在一个地方需要用到包中的一小个资源,例如一个2048*2048图集中的一个小icon。拷贝一份,并且放入到目前需要使用的包中,避免由于小的资源需求而引入大内存消耗。
资源工作流管理
作为程序,我们在资源上面花的精力自然是越少越好,但是如果没有好的工具链,好的流程,我们必定将会困在永远做不完的资源管理中。美术发过来的max文件或许需要经过你的导出、导入到Unity、拖成预制体、挂动画、挂碰撞盒等等的操作之后才能成为一个真正可用的资源。这个时候一个好的工具显得格外重要。
- uTomate,用于管理流程的Unity插件,我们可以通过简单的节点连接来对我们的资源进行一系列操作的配置。除此之外,我们还可以用它来做一键打包等功能。
- Defaulter – Custom Importer Defaults ,用于管理资源的导入统一化,通过路径来决定其中资源的格式,例如:贴图对应着的MaxSize、Format、Read&Write等等,还支持其他很多的资源,通过这个我们不再需要对每一个导入的资源进行手动的设置了,由于其开源的有点,我们也可以根据我们自己的需要进行优化。由于作者不再维护了,所以我们或许需要自己来进行编写。
- 熟悉一些简单的程序脚本,例如maxscript或者是ps中的ExtendScript ToolkitCS6。我就曾经自己写过一个自动切图的小插件,不过效率不是很行,但是语言本身并不难学,能给美术和程序自己带来很多方便,通过C#对命令行调用的方式集成到Unity中,相信整个工作会轻松不少。
- 利用Jenkins或者Hudson进行持续集成。人肉集成是对人力与资源的一种浪费,极其容易出现错误,而本地打包则大大占用了程序员的本地带宽,让程序员无法继续进行工。而通过配置Jenkins来自动实现可参数化的、稳健的、可持续的集成,项目组可以集中更多的力量来进行产品的迭代。
- 使用Spine或者Unity Anima2D来制作2D动画,可以事倍功半。
- 当然最靠谱的还是自己用C#来写工具,虽然会花一些时间,但是磨刀不误砍柴工,花一天时间写工具,今后的几个月当中可能会减少你好几天的工作量。好工具所带来的生产力可能大大超出你的想象。
资源的工作流除了用于生成资源,对于资源的管理也是非常的重要。
推荐的方式是程序使用更加灵活的git来进行管理,有条件的可以自己做一个gitlab服务器用于存放代码。而美术则使用局域网SVN进行美术资源的管理,程序可以将部分直接可用的美术资源直接链入项目当中,其他的则是通过上述提到的工作流工具来进行批量处理。