l

成都手游码农一枚
随笔 - 33, 文章 - 0, 评论 - 117, 引用 - 0
数据加载中……

[Unity3D]U3D开发项目总结

从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帧。

等等 暂时只回想起这么多,希望对大家有帮助,有问题可以探讨。

今天项目组换老大了,希望换人后上线能顺利,毕竟也花费了不少精力,周五也得离开了,想想也挺伤感的,游戏行业真不好混。



posted on 2014-12-04 00:05 l1989 阅读(12140) 评论(24)  编辑 收藏 引用 所属分类: 游戏

评论

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

游戏行业分分合合,聚聚散散是常事,的确容易伤感。但不要伤感太久,还有很多志同道合的人跟你在一起奋斗呢。
2014-12-04 10:19 | 陈冠希

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

(a) GitHub 上下载 Unity 官方 Mono库
。。。
代码加密这一块是写的思路还是真的这么做了?
我下载了,并且修改编译,启动后总是报错JNILoad错误。
不知道是不是版本未匹配。
你们成功使用了这个方案?
2015-02-04 19:50 | 陌上清

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

@陌上清
正式项目没用,只是自己测试过,Mono库版本要和U3D版本一致,分支中有各个版本。
2015-02-05 16:07 | shly

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

您好,关于代码加密这块,我们现在有个方案就是文中提到的修改mono。从官方github上下载了Mono2.12.x-Unity4.x及对应的编译工具包monobuildtools-Mono2.12.x-Unity4.x。但是编译不过出了问题,在centos7跟Ubuntu12.04上面配置环境后编译都出问题。。楼主有详细的步骤提供下么?感激不尽。
2015-03-09 16:04 | ljs

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

伙计,关注你好久啦,没想到你也从cocos转到U3D了,咱们经历很像啊,我当时是找寻cocos的富文本看到你的博客,哈哈,你写的好简单,后来在github上down了一个html解决方案,应该和你是同一份源码吧,改了源码,走了不少坑,最后还是顺利解决了,目前我也在搞U3D项目呢,正在刨坑和tian'keng,不多说啦,有机会再联系!
2015-03-16 11:59 | laukey

# re: [Unity3D]U3D开发项目总结[未登录]  回复  更多评论   

楼主有编译过unity-mono 4.3版本以上的么 4.3后的版本去掉了编译脚本 不懂咋编译了
2015-03-30 17:29 | lg

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

@ljs
你编译过了没有,我也遇见这种问题,qq:737871854
2015-06-26 10:50 | meij

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

@ljs
我尝试的Github上面 Unity4.6的mono版本

在Window 和Mac下均编译不过_(:з」∠)_ 目前卡着3天了 。。
请问你可有编译通过?
2015-07-02 15:48 | 喵喵丸

# re: [Unity3D]U3D开发项目总结[未登录]  回复  更多评论   

@喵喵丸
不好意思 后面的版本没有尝试过
2015-07-03 13:58 | azl

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

@azl
好吧。。还是谢谢你了~
2015-07-06 17:38 | 喵喵丸

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

@azl
我是用的mono-unity4.3版本,在ubuntu上源码编译通过,加密部分加入你说的简单混淆的代码,也编译通过,打包apk后,吧Assembly-CSharp.dll文件拿出来,使用ISpy工具,还是轻轻松松的吧代码给显示出来,没任何加密效果。。。。。
使用minizip加密算法,加入了unzip.h头文件,以及在mono_image_open_from_data_with_name函数中加入相关算法,因为加入了新的头文件,并引用相关函数,不知道如何编译了。。。。

如何破破破破破破破破破破破破。。。。。
2015-07-07 17:36 | meij

# re: [Unity3D]U3D开发项目总结[未登录]  回复  更多评论   

@meij
1.提取出APK中的Assembly-CSharp.dll混淆后放回去
2.再修改mono在加载的时候还原dll
2015-07-07 18:43 | azl

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

@azl
你提到的“1.提取出APK中的Assembly-CSharp.dll混淆后放回去
2.再修改mono在加载的时候还原dll ”

是先把unity项目打包apk,提取Assembly-CSharp.dll,使用混淆算法混淆候(加密),然后把加密后的Assembly-CSharp.dll放到apk包中,最后在mono的image.c代码中,进行反混淆(解密),把生成的libmono.so文件放入对应版本的unity中。是这样理解吗?

如此就是说,加密(混淆)部分代码是要另外写的,编译mono生成的libmono.so只是解密。
这样理解对不?

2015-07-07 19:28 | meij

# re: [Unity3D]U3D开发项目总结[未登录]  回复  更多评论   

@meij
是的 可以自己琢磨下 我也没在项目中用过 只是无聊玩了下
2015-07-07 20:20 | azl

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

@azl
编译mono生成libmono.so,对应版本的unity3d里面有好几个包含libmono的文件,其中androidplayer和androiddevelopmentplayer文件夹下均有armv7a包含libmono.so。
请问用生成的libmono.so文件覆盖那几个文件夹下的libmono.so,因为我试了几次,打包apk安装后,无任何图像显示。。。
2015-07-08 14:40 | meij

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

有解密算法,就有加密算法,能否贴一下简易的加密算法代码看一下吗?参考下,谢谢!对您可能很简单,对我这种菜鸟却帮助很大,麻烦贴主,发我qq邮箱也行737871854@qq.com
2015-07-08 20:09 | MKK

# re: [Unity3D]U3D开发项目总结[未登录]  回复  更多评论   

@meij
无图像显示有可能是dll解出来是错误的 可以检查下
2015-07-09 09:34 | azl

# re: [Unity3D]U3D开发项目总结[未登录]  回复  更多评论   

@MKK
把文件的每个字节去翻就可以了 或者移位等等
2015-07-09 09:35 | azl

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

@azl
网上资料好少,收集了一周的资料,下面是自己整理后感觉的流程:
1、修改image.c文件,注入解密代码

if (NULL != strstr(name, "Assembly-CSharp.dll"))
{
for (i=0; i < data_len;i++)
{
data[i] = ~data[i];
}
}
2、运行build_runtime_android.sh编译出libmono.so(builds/../armv7a/),将该.so文件覆盖unity3d中Data/..下的两个arm文件中的.so文件;
3、打包apk项目;
4、取出apk中的.dll文件,使用vs写的加密算法进行加密
int _tmain(int argc, _TCHAR* argv[])
{
FILE * fp;
FILE* pSaveFile;
char * filename_O = "Assembly-CSharp.dll";
char * filename_S = "Assembly-CSharp_QQ.dll";
long i;
long last;

if (fopen_s(&fp, filename_O, "rb") != 0)
{
printf("Can not open %s!\n", filename_O);
exit(0);
}
fopen_s(&pSaveFile, filename_S, "wb"); // 打开文件
fseek(fp, 0L, SEEK_END);
last = ftell(fp);
fseek(fp, 0L, SEEK_SET);

char *ret =(char *) malloc(last);
fread(ret, 1, last, fp);
for ( i = 0; i < last; i++)
{
ret[i] = ~ret[i];
fputc(ret[i], pSaveFile);
}
fclose(fp);
return 0;
}
加密后的dll文件为Assembly-CSharp_QQ.dll,将名字改回Assembly-CSharp.dll,再放入apk包中。
我一直是按照这个步骤做的,不知步骤有错没,或是加密或解密代码有错,导致总是成功不了,谢谢楼主。
2015-07-09 10:15 | MKK

# re: [Unity3D]U3D开发项目总结[未登录]  回复  更多评论   

@MKK
1.替换dll可以县城成eclipse工程文件,在替换dll,再打包,省的替换apk签名出问题
2.加解密可以先自己用解密的代码在本地测试一下能否还原,验证一下是不是加密有错误
2015-07-09 10:19 | azl

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

@azl
楼主回复的真快,好有爱!
加密后,在解密,我用ILSpy试过,可以正常解密,谢谢楼主给的意见,我使用eclipse替换dll试试,再次感谢!
2015-07-09 10:28 | MKK

# re: [Unity3D]U3D开发项目总结[未登录]  回复  更多评论   

感谢LZ 已经搞定 主要卡在编译上面了
2015-08-04 07:02 | LEE

# re: [Unity3D]U3D开发项目总结[未登录]  回复  更多评论   

感谢LZ 已经搞定 主要卡在编译上面了 Q32044538 期待交流
2015-08-04 07:03 | LEE

# re: [Unity3D]U3D开发项目总结  回复  更多评论   

楼主挖个坟 请问有没方法改变读入的dll的文件位置?例如sd卡 望赐教!感谢~
2016-06-28 20:35 | sping

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理