跳转至

Unity 6.3 — DOTS / Entities (ECS)

最后验证: 2026-02-13 状态: 生产就绪(Entities 1.3+,Unity 6.3 LTS) 包: com.unity.entities(Package Manager)


概述

DOTS(数据导向技术栈) 是 Unity 的高性能 ECS(实体组件系统)框架。它专为大规模(数千到数万个实体)的游戏而设计。

DOTS 适用于:

  • RTS 游戏(数千个单位)
  • 模拟(人群、交通、物理)
  • 程序化内容生成
  • 性能关键系统

请勿将 DOTS 用于:

  • 小型游戏(额外开销不值得)
  • 需要频繁进行结构性更改的玩法
  • 大量使用 UnityEngine API(使用 MonoBehaviour 更简单)

⚠️ Knowledge Gap: Entities 1.0+(Unity 6)是对 0.x 的完全重写。许多针对 Entities 0.x 的教程现在已经过时。


安装

通过 Package Manager 安装

  1. Window > Package Manager
  2. Unity Registry > Search "Entities"
  3. 安装:
  4. Entities(ECS 核心)
  5. Burst(LLVM 编译器)
  6. Jobs(自动安装)
  7. Mathematics(SIMD 数学)

核心概念

1. 实体

  • 轻量级 ID(int)
  • 没有行为,只是一个标识符

2. 组件

  • 仅包含数据(没有方法)
  • 实现 IComponentData 的结构体

3. 系统

  • 对组件进行操作的逻辑
  • 实现 ISystem 的结构体

4. 原型

  • 组件类型的唯一组合
  • 具有相同组件的实体共享同一个原型

基础 ECS 模式

定义组件

using Unity.Entities;
using Unity.Mathematics;

// ✅ Component: Data only, no methods
public struct Position : IComponentData {
    public float3 Value;
}

public struct Velocity : IComponentData {
    public float3 Value;
}

定义系统

using Unity.Entities;
using Unity.Burst;

// ✅ System: Logic that processes entities
[BurstCompile]
public partial struct MovementSystem : ISystem {
    [BurstCompile]
    public void OnUpdate(ref SystemState state) {
        float deltaTime = SystemAPI.Time.DeltaTime;

        // Query all entities with Position + Velocity
        foreach (var (transform, velocity) in
            SystemAPI.Query<RefRW<Position>, RefRO<Velocity>>()) {

            transform.ValueRW.Value += velocity.ValueRO.Value * deltaTime;
        }
    }
}

创建实体

using Unity.Entities;
using Unity.Mathematics;

public partial class EntitySpawner : SystemBase {
    protected override void OnUpdate() {
        var em = EntityManager;

        // Create entity
        Entity entity = em.CreateEntity();

        // Add components
        em.AddComponentData(entity, new Position { Value = float3.zero });
        em.AddComponentData(entity, new Velocity { Value = new float3(1, 0, 0) });
    }
}

混合 ECS(MonoBehaviour + ECS)

Baker(将 GameObject 转换为 Entity)

using Unity.Entities;
using UnityEngine;

public class PlayerAuthoring : MonoBehaviour {
    public float speed;
}

public class PlayerBaker : Baker<PlayerAuthoring> {
    public override void Bake(PlayerAuthoring authoring) {
        var entity = GetEntity(TransformUsageFlags.Dynamic);

        AddComponent(entity, new Position { Value = authoring.transform.position });
        AddComponent(entity, new Velocity { Value = new float3(authoring.speed, 0, 0) });
    }
}

工作原理:

  1. 在编辑器中将 PlayerAuthoring 添加到 GameObject
  2. Baker 会在运行时自动将其转换为 Entity
  3. 该 Entity 拥有 Position + Velocity 组件

查询

查询所有带有组件的实体

foreach (var (position, velocity) in
    SystemAPI.Query<RefRW<Position>, RefRO<Velocity>>()) {

    position.ValueRW.Value += velocity.ValueRO.Value * deltaTime;
}

使用 Entity 进行查询

foreach (var (position, velocity, entity) in
    SystemAPI.Query<RefRW<Position>, RefRO<Velocity>>().WithEntityAccess()) {

    // Access entity ID
    Debug.Log($"Entity: {entity}");
}

使用过滤器查询

// Only entities with "Enemy" tag
foreach (var position in
    SystemAPI.Query<RefRW<Position>>().WithAll<EnemyTag>()) {
    // Process enemies only
}

Jobs(并行执行)

IJobEntity(并行 foreach)

using Unity.Entities;
using Unity.Burst;

[BurstCompile]
public partial struct MovementJob : IJobEntity {
    public float DeltaTime;

    // Execute runs in parallel for each entity
    void Execute(ref Position position, in Velocity velocity) {
        position.Value += velocity.Value * DeltaTime;
    }
}

[BurstCompile]
public partial struct MovementSystem : ISystem {
    public void OnUpdate(ref SystemState state) {
        var job = new MovementJob {
            DeltaTime = SystemAPI.Time.DeltaTime
        };
        job.ScheduleParallel(); // Parallel execution
    }
}

Burst 编译器(性能)

启用 Burst

using Unity.Burst;

[BurstCompile] // 10-100x faster than regular C#
public partial struct MySystem : ISystem {
    [BurstCompile]
    public void OnUpdate(ref SystemState state) {
        // Burst-compiled code
    }
}

Burst 限制:

  • 不允许托管引用(类、字符串等)
  • 仅允许 blittable 类型(结构体、基元类型、Unity.Mathematics 类型)
  • 不允许异常

Entity Command Buffers(结构性更改)

延迟的结构性更改

using Unity.Entities;

public partial struct SpawnSystem : ISystem {
    public void OnUpdate(ref SystemState state) {
        var ecb = new EntityCommandBuffer(Allocator.Temp);

        // Defer entity creation (don't modify during iteration)
        foreach (var spawner in SystemAPI.Query<Spawner>()) {
            Entity newEntity = ecb.CreateEntity();
            ecb.AddComponent(newEntity, new Position { Value = spawner.SpawnPos });
        }

        ecb.Playback(state.EntityManager); // Apply changes
        ecb.Dispose();
    }
}

Dynamic Buffers(类似数组的组件)

定义动态缓冲区

public struct PathWaypoint : IBufferElementData {
    public float3 Position;
}

使用动态缓冲区

// Add buffer to entity
var buffer = EntityManager.AddBuffer<PathWaypoint>(entity);
buffer.Add(new PathWaypoint { Position = new float3(0, 0, 0) });
buffer.Add(new PathWaypoint { Position = new float3(10, 0, 0) });

// Query buffer
foreach (var buffer in SystemAPI.Query<DynamicBuffer<PathWaypoint>>()) {
    foreach (var waypoint in buffer) {
        Debug.Log(waypoint.Position);
    }
}

标签(零大小组件)

定义标签

public struct EnemyTag : IComponentData { } // Empty component = tag

使用标签进行过滤

// Only process entities with EnemyTag
foreach (var position in
    SystemAPI.Query<RefRW<Position>>().WithAll<EnemyTag>()) {
    // Enemy-specific logic
}

系统排序

显式排序

[UpdateBefore(typeof(PhysicsSystem))]
public partial struct InputSystem : ISystem { }

[UpdateAfter(typeof(PhysicsSystem))]
public partial struct RenderSystem : ISystem { }

性能模式

区块迭代(最大性能)

public void OnUpdate(ref SystemState state) {
    var query = SystemAPI.QueryBuilder().WithAll<Position, Velocity>().Build();

    var chunks = query.ToArchetypeChunkArray(Allocator.Temp);
    var positionType = state.GetComponentTypeHandle<Position>();
    var velocityType = state.GetComponentTypeHandle<Velocity>(true); // Read-only

    foreach (var chunk in chunks) {
        var positions = chunk.GetNativeArray(ref positionType);
        var velocities = chunk.GetNativeArray(ref velocityType);

        for (int i = 0; i < chunk.Count; i++) {
            positions[i] = new Position {
                Value = positions[i].Value + velocities[i].Value * deltaTime
            };
        }
    }

    chunks.Dispose();
}

从 MonoBehaviour 迁移

// ❌ OLD: MonoBehaviour (OOP)
public class Enemy : MonoBehaviour {
    public float speed;
    void Update() {
        transform.position += Vector3.forward * speed * Time.deltaTime;
    }
}

// ✅ NEW: DOTS (ECS)
public struct EnemyData : IComponentData {
    public float Speed;
}

[BurstCompile]
public partial struct EnemyMovementSystem : ISystem {
    public void OnUpdate(ref SystemState state) {
        float dt = SystemAPI.Time.DeltaTime;
        foreach (var (transform, enemy) in
            SystemAPI.Query<RefRW<LocalTransform>, RefRO<EnemyData>>()) {
            transform.ValueRW.Position += new float3(0, 0, enemy.ValueRO.Speed * dt);
        }
    }
}

调试

实体层级窗口

Window > Entities > Hierarchy

  • 显示所有实体及其组件
  • 按原型、组件类型过滤

实体分析器

Window > Analysis > Profiler > Entities

  • 系统执行时间
  • 每个原型的内存使用情况

来源

  • https://docs.unity3d.com/Packages/com.unity.entities@1.3/manual/index.html
  • https://docs.unity3d.com/Packages/com.unity.burst@1.8/manual/index.html
  • https://learn.unity.com/tutorial/entity-component-system

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/Claude-Code-Game-Studios