先说结论:如果你的团队少于10个人,做的不是那种需要同屏一万个单位的模拟类游戏,那Unity DOTS大概率不是你的最优解。这不是标题党,是我从2022年开始在一个模拟经营项目里全面上DOTS,折腾了三年,最后又部分退回传统写法的真实感受。今天写出来,就是想让那些看了官方Demo和吹捧文章就热血沸腾的开发者冷静一下。
先聊聊性能对比。网上很多测试说ECS能轻松驱动10万GameObject,我也复现过,纯跑Transform矩阵更新,ECS确实比GameObject快了三倍左右(我自己的测试数据是:2万物体旋转更新,传统写法每帧耗时11.2ms,Job System + ECS是3.7ms)。但这只是把数据从托管堆换到了非托管内存,并且没有触发任何复杂的碰撞和渲染。一旦你加了Physics Collider,哪怕是用Physics.SyncTransforms,Job System的并发优势立马被物理引擎的同步瓶颈吃掉,性能直接掉到和传统写法一个级别。我实测过,在9000个带Collider的实体上做平移,ECS比GameObject只快了18%,而且多出来一堆computed state的序列化问题。
再说开发效率。传统GameObject里一个角色的移动逻辑,你写个MonoBehaviour的Update函数,改完立刻Play模式看效果。ECS呢?你得拆成Component、System,还要考虑System的Order、ScheduleParallel的依赖链。就为了个移动,你得写十几个文件。尤其是当你想用Burst编译器的完整功能时,必须在代码里手动标记[DisableAutoCreation]和[CreateAfter]来管理System更新顺序,否则每次改一个数学运算就可能引发意外的JIT编译异常。我记得有一次调试一个位置不同步的bug,原因是我的System跑在了LateUpdate之后,但另一个System临时切换到了SystemBase,结果Burst优化掉了某个未使用的字段,导致同步逻辑静默失败。这种问题,你在没有纯托管GC压力的传统环境下根本不会遇到。
还有内存和序列化。DOTS的内存是高效了,但代价是你要自己管理生命周期。用EntityManager.AddComponent和SetComponentData,没有引用跟踪,也没法用UnityEvent或Inspector拖拽赋值。我们项目里有个技能配置表,本来设计成ScriptableObject里存List
我的最终结论是:如果你做的是纯CPU密集型、需要超10万简单生命体(比如群聚、粒子、模拟)的项目,DOTS值得投入。但如果是常规RPG、射击游戏,哪怕同屏只有500个敌人,传统GameObject加上对象池和批处理优化,完全够用。对中小团队来说,DOTS的学习成本、编辑器工具链的缺失、以及和现有Unity生态的割裂(比如不支持Burst下的LINQ、反射、字符串操作),都会成为实际工期里看不见的杀手。我现在这个项目,只保留了计算流体和草地渲染那两块ECS代码,其余逻辑全部改回了GameObject。不是ECS不好,而是我们误以为它是一把万能钥匙,结果发现它只是一把结构极其特殊的锁。如果你正在犹豫,先拿一个小原型跑两周,如果两个周内你的团队还搞不定一个简单的实体运动,就该回头了。
顺便提一嘴,Unity 2022 LTS的DOTS 1.0版本已经稳定了许多,但稳定不代表好用。新出的Unity 6里ECS也开始支持更多GameObject互操作了,但本质上仍然需要你按ECS的思维去组织数据。我不会再去和人争论谁更高明,毕竟工具只有适合自己的需求才有价值。