Unity DOTS 架构下的高性能游戏开发实践
深入 Entity Component System 架构,探索 Unity 高性能开发的正确姿势。
DOTS 概述
DOTS(Data-Oriented Technology Stack)是 Unity 近年来最重要的架构变革。它包含三个核心组件:
- ECS(Entity Component System):面向数据的实体组件系统
- Job System:多线程任务调度系统
- Burst Compiler:高性能 IL 到原生代码的编译器
三者结合,可以让游戏性能提升一个数量级。
Entity Component System 基础
核心概念
ECS 与传统 OOP 的最大区别在于数据与逻辑的分离:
// Component:纯数据,无逻辑
public struct Position : IComponentData
{
public float3 Value;
}
// System:纯逻辑,无数据
public partial struct MovementSystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
foreach (var (pos, vel) in
SystemAPI.Query<RefRW<Position>, RefRO<Velocity>>())
{
pos.ValueRW += vel.ValueRO * SystemAPI.Time.DeltaTime;
}
}
}
组件类型
| 组件类型 | 用途 | 内存布局 |
|---|---|---|
| IComponentData | 可读写组件 | 紧凑数组 |
| IEnableableComponent | 可开关组件 | 位掩码 |
| ISharedComponentData | 共享组件 | 按值分组 |
| BufferElementData | 动态数组 | 连续内存 |
Job System 深度应用
IJobEntity:ECS 查询的并行化
[BurstCompile]
public partial struct CollisionJob : IJobEntity
{
public float DeltaTime;
void Execute(ref Position pos, in Velocity vel, in Collider col)
{
pos.Value += vel.Value * DeltaTime;
// 碰撞检测逻辑...
}
}
Job 依赖管理
public partial struct GameSystem : ISystem
{
public void OnUpdate(ref SystemState state)
{
var job1 = new MovementJob().ScheduleParallel(state.Dependency);
var job2 = new CollisionJob().ScheduleParallel(job1);
var job3 = new RenderJob().Schedule(job2);
state.Dependency = job3;
}
}
Burst Compiler 优化技巧
使用 SIMD 指令
[BurstCompile(FloatMode = FloatMode.Fast)]
public struct SimdJob : IJob
{
[ReadOnly] public NativeArray<float4> Input;
[WriteOnly] public NativeArray<float4> Output;
public void Execute()
{
for (int i = 0; i < Input.Length; i++)
{
Output[i] = math.sqrt(Input[i] * Input[i] + 1.0f);
}
}
}
实战案例:万人同屏
在某 SLG 项目中,需要同时渲染 10000+ 单位的战斗场景。
性能对比
| 场景 | MonoBehaviour | DOTS | 提升 |
|---|---|---|---|
| 1000 单位 | 45 FPS | 120 FPS | 2.7x |
| 5000 单位 | 12 FPS | 90 FPS | 7.5x |
| 10000 单位 | 3 FPS | 60 FPS | 20x |
踩坑记录
- 主线程访问:ECS World 只能在主线程访问,Job 中无法直接创建/销毁 Entity。需要使用 EntityCommandBuffer。
- 内存对齐:Burst 要求数据按 16 字节对齐。自定义结构体注意内存布局。
- 编译时间:Burst 编译会显著增加编译时间,建议在开发阶段关闭。
总结
DOTS 是 Unity 性能优化的终极武器,但它不是银弹。适合大量同类实体(RTS、弹幕游戏、模拟类)和计算密集型逻辑。不适合 UI 系统和少量实体的简单游戏。掌握 DOTS 需要转变思维方式——从面向对象到面向数据。