从2月份到现在第一个U3D项目也基本收工,虽然项目结局不是太好,但总算也是成功卖掉并上线,总结将近10个月的时间大家从端游转到手游或从COCOS2转到U3D的整个开发过程。
1.资源
无疑这是整个项目我觉得做的最差的地方,也是前期最为忽略的地方,犹豫U3D组件式架构的原因和本身资源打包加载的一个限制,导致后期项目资源异步加载以及动态更新很难实现。
起初犹豫是项目玩法参考《印第安大冒险》,在导出它的包查看了它的结构以及部分实现的代码后,发现基本也未作任何资源管理,资源基本上一个关卡一个场景的方式组织,所以也就按他的方式,只是简单的按场景、特效、UI等进行了简单的划分。
但是随着关卡的复杂性的增加,游戏复杂性的增加,问题也随之而来。
项目问题以及方案:
(1) 场景加载慢,无法异步加载
因为没用AB管理资源,所以很难实现异步加载,但是场景已经完成到了某种程度,也很难重新设计资源加载方式,所以临时找了另一种方案。、
a.先将原始资源移动到Resources目录先,这样的原因是为了在加载场景是预加载纹理、模型等资源,随之而来的问题便是Resources下的目录中不能保留不需要的资源,否则会一起导入安装包,导致安装包庞大,最后写了一个编辑器扩展脚本在打包时候清理掉所有游戏未引用的资源。方法是找到所有场景以及与之的依赖资源并记录,找到所有资源在一处记录的资源,剩余资源统一删除。
b.扩展一个编辑器脚本生成当前场景所有依赖资源列表,生成预加载文件,在加载文件时读取并通过Resource.Load加载并保存,切换时候在释放。为了实现模拟异步加载的效果,加载时在一个新的协程中加载,加载两个返回一帧。
(2) 运行时怪物创建卡顿
同样这个也是由于这个原因造成的,解决方案相对取巧,由于怪物是有触发器创建,所有在加载场景时候会预先创建所有怪物并隐藏,知道触发后在显示出来。
(3) 特效、技能等预制资源卡顿
同样这个也是由于这个原因造成的,解决方案,这个比较传统,增加了一个预制缓存池,创建场景时候会对指定配置的特效做缓存,创建时候从缓存中取出,用完还回去就可以了。
(4) 资源更新
这个暂时只能妥协,只做了配置文件的更新
理想解决方案:
(a) 以Prefab为基本打包力度,为特效、UI节点、角色等等保存为Prefab。
(b) 将所有代码、Shader、等等公用基础资源打包到Common.ab。
(c) Push:Common.ab的基础上打包UI/Audio/Effect/Actor...等分支下的Common_*.ab。
(d) Push:Common_*.ab的基础上打包UI/Audio/Effect/Actor...下的预制到 *.ab。
(e) 加载加载Common.ab,在加载分支支援时候先加载相应的Common_*.ab后在加载特定的ab。
(f) 加载可以采用异步加载形式,场景创建时候可以先创建空节点,等异步加载完成后在创建并挂接到该节点上。
(g) 关于Level,打包时候打包基本场景以及关照贴图,加载后在动态加载响应节点数据并挂接上去
2.特效
首先这边的特效基本是有端游转过来的,而前期对特效没有做一些规范性的限制,导致一些特效复杂度相当高,以及里面包含大量Animator(这个损耗相当大)。
其次特效未作统一的管理,而仅仅是简单的做成一个Prefab。造成后期特效不是太好优化。
理想解决方案:
(a) 提供一个特效编辑器,组织特效,发布的时候检查并提示出一些必要的警告方便特效人员修改,同时未特效预制加入自动管理脚本。
(b) 或采用一些比较好的插件 FX Maker 等。
3.场景
场景最大的问题同样是没有好的规范,导致前期场景模型用了大量的多维材质,比如一个石头可能有 表面/中部/底部/边缘 等四个材质等等。
理想解决方案:
(a) 尽量只使用一中材质,当然有些工具比如Mesh Banker 可以拿来优化。
(b) 地表装饰无尽量将贴图合并到一张Atlas公用,减少批次,比较特殊的情况比如 Repeat Mode的贴图可不处理。
(c) Static Batch 虽然能够做一定的优化,但是会大大的增加Level暂用的硬盘空间,所以可以根据实际场景视角等来确定是否开启以便减少生成包的大小。
4.动作
操控相对简单,虽然Animator很强大,单可控性却不是很高,所以选择使用Animation,通过Layer进行状态融合处理。AddMixTransform 可以进行上下半身或者特殊部分动作混合。
附带:关于Animator性能,场景中Animator过多会造成CPU消耗过高,而Aniamtion有可见在更新的状态选项可以进行控制,Animator却不行,因为是统一管理,所以需要注意。
5.NGUI
NGUI确实很强大,有自己的批渲染,这类也不需要多说,其中有两个可以分享的地方
(a) 特效与NGUI层级,实际上NGUI/Panel/DrawCall会有一个RenderQuene,为了层级正确我们应带改变特效material.renderququne = DrawCall.RenderQuene + 1,这样特效就可以在正确的面板上显示与遮挡。
(b) DrawCall优化,可以利用 Panel:ShowDrawCall工具手动调整Panel中空间的order来减少DrawCall。
6.代码加密
代码加密相对麻烦,因为其实整个过程中也通过ISpy查看过不少游戏的代码,基本很少做加密的,少量做了混淆。
理想解决方案:
(a) GitHub 上下载 Unity 官方 Mono库
(b) 找到 image.c : mono_image_open_from_data_with_name 函数:
增加代码:(简单的混淆DLL)
if (NULL != strstr(name, "Assembly-CSharp.dll"))
{
for (; i < data_len;)
{
data[i] = ~data[i];
i += k;
k += 1;
}
}
后编译生成 libmono.dll/so 到相应平台
(c)将Assembly-CSharp.dll反向混淆
7. 纹理压缩
用disunity导出U3D打包后的资源法线android下纹理实际上是经历过一次转换的:
带Alpha通道贴图-> TGA 未压缩格式 / 除非设置 通常都带Mipmap
不带Alpha通道贴图-> KTX (ETC1 android) 不带Mipmap
显然为了减少纹理对GPU芯片带宽的浪费以及对内存的浪费android下应当使用ETC1,而且ETC压缩失真不算严重,验证可接受。
那么对于带Alpha通道的贴图应该如何处理?解决方案1.提取Alpha为单独的Alpha通道贴图 2.提取Alpha为灰度图在保存为ETC1(默认会转换)。
这样有效提高程序性能同时也相应的会减少压缩后包的大小。因为TAG不然缩与ETC压缩后在ZIP压缩还是有一定的空间大小差距。
8.其他一些特效
shadow_gun 中有很多不错的 shader 可以用用 比如EnvCube可以支持带lingthingmap的Cube反射材质,做冰柱等效果非常好。
water 等可以简单的用一张nosiy贴图加Cube反射模拟,效果也可以接受。
unity / image effect/ MothionBlur 可以做Boss死亡特效 配合 Time.timeScale K帧。
等等 暂时只回想起这么多,希望对大家有帮助,有问题可以探讨。
今天项目组换老大了,希望换人后上线能顺利,毕竟也花费了不少精力,周五也得离开了,想想也挺伤感的,游戏行业真不好混。