那些事情是用Unity开发项目应该一开始规划好的？如何避免后期酿成巨坑？
总的来说，unity没有啥天坑。只要肯研究，后期都能改进，也都不会影响到上线。 小坑太多，说不完。unity上手容易坑太多，基本事件机制，生存周期，场景和资源管理，mono虚拟机的gc机制都是坑。 要说的话，真正影响到架构的是（排序） 1. 是否要用lua 2. （对于需操作的游戏）客户端游戏如何做战斗验证 ----------------------------------------------------- 公司的话，推荐： 参加Unity年会 购买Unity的官方支持问答平台，人有源代码，还能找总部 ----------------------------------------------------- 下面列举小坑吧。不建议都绕开，毕竟没有那么多时间做前期调研的。 对应版本Unity4.x 1. 客户端程序层面 总的来说C#超级给力的，不过别玩脱了 1) mono虚拟机gc Unity的mono虚拟机使用不分代的gc算法，临时对象积攒起来，导致重量级GC游戏频繁卡顿。 Unity官方：认真review每帧20B以上，以及一次2K以上的GC Alloc的行为。传闻：Unity5会改进。 推荐阅读： 评价：请像C++一样精确了解各种行为的gc，foreach 都不要随便用。严重，但游戏是可以卡巴卡巴上线的。后期一位核心开发人员修2~3周。 2) 苹果aot编译问题：模板问题 mono在苹果上采用aot将C#编译为静态代码。首先，依赖于动态代码生成的复杂模板容易运行时崩溃；其次，mono会将客户端生成一个库。模板代码实例化容易膨胀导致该库超过40M而无法链接。 实战：碰到了改写法吧。不过我本人是静态类型检查派的。 3) 少用coroutine yield只支持try--finally，与异常体系兼容性极差；难以提供返回值；异步本身是非线性的，很难保证逻辑完备 实战：复杂异步逻辑用状态机。不致命，多修bug也能抗过。 4) 自行处理配置数据序列化 严重影响配置读取速度。C#自带的xml序列化很慢，自带的二进制序列化也不够快。 实战：打包配置考虑protobuf或者代码生成器。中后期一周左右。 5) 反射 手机上jit情况下，第一次反射一个类很慢。乱用足够影响启动速度。 6) 本地化 如果公司习惯于做海外市场，一开始就可以考虑全套本地化方案。后期改需要一个人1~2个月工作量。 2 资源优化 Unity资源优化，一个靠谱的TA很重要。 1) 资源内存占用 512内存机器能用的资源大概只有50~60M。 需透彻研究贴图。考虑换皮怪资源复用、UI的图集合理化。 没有UI优化经验的话，强烈建议一个核心开发死跟，像抠代码优化一样优化图集总结经验。这个后期很难收场。 每个粒子发射器占用10K内存；有些项目在动画上会有内存问题。 2) 关注资源包大小 最大的是贴图和骨骼动画。贴图关注内存即可。骨骼动画可以占到模型的一半大小，重做的话有各种优化方案。但超标后期也很难收场。 3) 依赖打包 Unity4.x和Unity5完全不同。其中Unity4.x机制庞大繁杂容易错，要有心理准备。扯一些要点： * 一定要搞清其内存占用和生存周期。要实测，特别容易跌眼镜。 * 每个API都有坑。我个人目前推荐压缩模式、LoadFromCache，此时不能拆太碎。战斗前预加载。 * shader加载慢，应当放入依赖包 * bundle不能重名 4) 场景、drawcall、camera 场景面多了考虑动态batching 不同材质透明物体（例如粒子）穿插可能引起drawcall暴增。 camera是重型对象，越少越好 5) svn 资源选Text模式、显式保存.meta，便于版本管理。资源分人或者锁了改，规避冲突。 3 Unity 和Flash一样容易学的3D编辑器 1 ) 事件机制 Unity事件机制很不好用。单个对象，Awake，Start，Enable调用时机相当复杂。Unity完全不保证多个对象的事件执行顺序，导致很多人绕开Start。不恰当的使用事件，很容易导致父子对象不在同一帧出现，画面不干净。 Destroy操作是延迟的，对象会活到帧的结尾，然后必定销毁。库级设计时，必须考虑到这一点(例如对象池/动画库)。 2) 资源管理 只说Unity4.x。合理做法是依赖很卡的UnloadUnusedAssets、LoadScene清理无引用资源（另注意前者是异步的），或者Bundle.Unload(true)，这些方案各有限制。试图更细粒度手工清理的困难在于，并不存在系统性文档解释Unity资源的分类和生存周期，且Destroy操作很保守。例如，销毁mesh时，并不会销毁material、texture，更不会清理脚本资源。 此外，特定的普通操作会造成资源克隆。例如访问Renderer.meterial，Animation.AddClip。 4 NGUI 久经验证的掉链子王。新项目也可以尝尝uGUI 1) panel重绘 widget改变后，所在panel需要生成多边形，很慢，坑新人没商量，注意合理分panel。panel中多边形过多会爆（貌似是65535个顶点？）。 uGUI原理相同，就是c代码比C#快不少。 2) panel渲染顺序 搞清楚ui上放置3D物体咋办，ui如何和特效混合排序。 3) 策划/美术ui规范 潜规则很多。Anchor、动画不可作用于同一个物体。widget必须是panel的子节点，不然他就会自己造panel，经常搞出乱子。再加上上面的panel规则等，要策划美术折腾ui可费神了。 项目组自制UI编辑器自然是极好的，不过不一定必要。 4) 创建速度慢 由于序列化字段多，NGUI对象创建可导致卡顿。多状态对象不要靠隐藏-显示，而要动态创建。尤其是状态中包含粒子发生器/Animation，这俩还有内存问题（10K一个）。 5) 与Unity事件机制强耦合 与Unity的事件机制强耦合，不完备，容易有bug。例如，panel绘制依赖于LateUpdate。coroutine中同时关闭旧界面，创建新界面，此时当前帧 LateUpdate 已过，表现为有一帧画面为空白。 ---------------------------------------------------------------------------------------- 正文分割线 Q:回答 在评论区的问题  “能详细说说使用 UnloadUnusedAssets()、LoadScene() 等等 APIs 的细节吗? 有没有替代方案 ”。 A: 需要区分 SceneMemory和Asset。Instantiate出的GameObject及其Component属于SceneMemory。贴图、Mesh、Shader、自定义Component代码、AnimationClip等，还有AssetBundle中的GameObject及其Component属于Asset。 说一下UnloadUnusedAssets慢的原因。核心问题在于，Unity希望C#代码可以引用资源，而且能维持其资源生命周期。然后Unity决定每次UnloadUnusedAssets都去扫描所有C#对象！这个挺慢的。 从API看，下面是比较原汁原味Unity的模式，都避免了关卡中间UnloadUnusedAssets： A. 静态关卡 关卡进入前加载所有资源，在关卡结束后一次性清理。特别的，Unity觉得你应该使用Scene，他的lightmap、navimesh都是与Scene绑定的。这种情况下，都不需要调用UnloadUnusedAssets()。优点是关卡非常流畅，但是关卡必须是有限大小，有限内容。 B. AssetBundle为单位管理动态资源 动态资源放到AssetBundle中，不再使用时，用Unload(true)彻底删除Asset。缺点是和A方案比起来加载可能会卡；此外不卸载的bundle本身，合到一起经常有10~30M的额外内存占用。 具体游戏，怪物、特效、UI、玩家用A还是B就是权衡问题了。 最后，如果觉得Unity不好，可以考虑全手动管理资源，能绕开一些限制，多榨一些性能。如果项目可以有一个人专门深度优化技术，可以考虑尝试，时间两个月起，也会引入不少bug。不少项目是主程做这事，也有让较厉害的程序做这的。