Unity Enitity Component System 参考手册 - 2.3 Component

基于0.11.1-preview 4 版本

2.3 Components

component是ECS体系结构的三个主要元素之一。它们代表游戏或应用程序的数据。entity是为component集合建立索引的标识符,而系统则提供了行为。ECS中的component是具有以下 “标记接口”(marker interfaces) 之一的结构:

ECS中的component是具有以下“标记接口”之一的结构:

  • IComponentData 用于通用component和chunk component。
  • IBufferElementData 将动态缓冲区与entity相关联。
  • ISharedComponentData 按archetype中的值,对entity进行分类或分组。有关更多信息,请参见Shared Component Data
  • ISystemStateComponentData 将system特定的状态与entity相关联,并检测何时创建或销毁各个entity。有关更多信息,请参见System State Components
  • ISharedSystemStateComponentData 共享状态和system状态数据的组合。请参阅[System State Components
  • `Blob assets 尽管从技术上讲Blob不是component,但您可以使用Blob asset来存储数据。Blob asset可以由一个或多个component,通过使用BlobAssetReference进行引用,并且是不可变的。您可以使用Blob asset在asset之间共享数据,并访问C# job中的数据。

EntityManager将若干个component的组合,组织到archetype中。它将具有相同archetype的所有entity的component,一起存储在称为chunk的内存chunk中。给定chunk中的entity均具有相同的componentarchetype。

该图说明了ECS如何按archetype存储component数据chunk。共享component和chunk component是例外,因为ECS将它们存储在chunk的外部。这些component类型的单个实例适用于适用chunk中的所有entity。此外,可以选择将动态缓冲区存储在chunk之外。即使ECS不在chunk内存储这些类型的component,在查询entity时,通常也可以将它们与其他component类型视为一类。

2.3.1 General purpose components

ComponentData在Unity中(在标准ECS术语中也称为组件),是一个仅包含entity的实例数据的结构。ComponentData不应包含用来访问数据的方法。您应该在system中实现所有游戏逻辑和行为。这有点类似于UnityEngine.Component类,但是只包含成员变量。不包含成员方法。

Unity ECS API提供了一个名为IComponentData的接口,您可以在代码中实现该接口,以声明通用组件类型。

2.3.1.1 IComponentData

传统的Unity组件(包括MonoBehaviour)是面向对象的类,其中包含行为的数据和方法。IComponentData是纯ECS样式的组件,这意味着它没有定义任何行为,仅定义了数据。您应该实现IComponentDatastruct而不是class,这意味着默认情况下,它是通过值而不是通过引用复制的。通常,您需要使用以下模式来修改数据:

1var transform = group.transform[index]; // Read
2transform.heading = playerInput.move; // Modify
3transform.position += deltaTime * playerInput.move * settings.playerMoveSpeed;
4group.transform[index] = transform; // Write

继承自IComponentData接口的结构不得包含对托管对象的引用。这是因为这种结构不被存放在托管堆中。

2.3.1.2 Managed IComponentData

使用托管IComponentData(即,IComponentData使用class而不是进行声明struct)有助于将现有代码以零碎的方式移植到ECS,与不适合的托管数据进行互操作ISharedComponentData,或者为数据布局提供archetype。

这些组件的使用方式与值类型相同IComponentData。但是,ECS在内部以完全不同(且较慢)的方式处理它们。如果不需要托管组件支持,需定义一个UNITY_DISABLE_MANAGED_COMPONENTS宏,以防止误用上它。

因为托管IComponentData是托管类型,所以与值类型的IComponentData相比,它有以下的性能缺点:

  • 不能与Burst编译器一起使用
  • 不能在JOB结构中使用
  • 它不能使用chuck内存
  • 需要使用GC

您应该尝试限制托管组件的数量,并尽可能使用 blittable类型 (即值类型)。

继承实现托管IComponentData接口必须实现IEquatable<T>接口并重写Object.GetHashCode()。此外,出于序列化的目的,这个继承实现的类必须是默认可构造的。必须在主线程上设置component的值。为此,请使用EntityManager或EntityCommandBuffer。由于这种托管component是引用类型,因此与ISharedComponentData不同,可以更改component的值而无需在块之间移动entity。这不会创建一个同步点。

尽管在逻辑上将托管component与值类型的component分开存储,但它们仍然有助于entity的EntityArchetype定义。这样,向entity添加新的托管component,如果尚不存在匹配的archetype,仍会导致ECS创建新的archetype,并将entity移至新的Chunk。

有关示例,请参见文件:/Packages/com.unity.entities/Unity.Entities/IComponentData.cs。