从零开始的游戏开发 —— Component 组件

组件是实体组件系统体系结构的三个主要元素之一。它们代表您的游戏或应用程序的数据。实体是为您的组件集合建立索引的标识符,而系统则提供了行为。

组件类型

在ECS中的组件是具有以下“标记接口”之一的结构体:

  • IComponentData - 作为通用组件和块(Chunk)组件
  • IBufferElementData - 将动态缓冲区与实体相关联
  • ISharedComponentData - 按原型中的值对实体进行分类或分组,共享组件
  • ISystemStateComponentData - 将系统特定状态与实体相关联,并检测何时创建或销毁单个实体,系统状态组件
  • ISharedSystemStateComponentData - 共享状态和系统状态数据的组合,共享系统状态组件
  • Blob assets - Blob assets原则上不是组件,但可以用来存储数据

继承不同的接口可将组件分成不同的类型,虽然大致的组件基本上都差不多,但是在一些细节方面,不同类型有细微的差别。

在阅读下面的内容之前,有必要解释一下在ECS架构中原型(Archetypeh)和块(Chunk)的概念。

:所有实体的组件存放的内存块

原型:所有具有相同组件的块的内存块

上图很清晰的说明了原型和块的区别,已经ECS中存储的方式,值得一提的是,有些组件并不存放在块中,包括共享组件和块组件,ECS将他们存储在块外部,这是因为这些组件的的单个实例化对象适用于块中所有的实体。此外,你也可以选择将动态缓冲区存储在块之外。即使ECS不在块内,你在查询实体时通常也可以将他们与其他组件类型等同。

IComponentData

传统的Unity组件是面向对象的类,其中包含数据和方法。继承自IComponentData的是纯ECS组件,这意味着他没有定义任何方法,仅仅定义了数据,所以应该把IComponentData实现为结构体(Struct)而不是类,这意味着默认情况下,他是值类型而不是引用类型,要修改特定的值只能通过覆盖来修改。

var transform = group.transform[index]; // Read

transform.heading = playerInput.move; // Modify
transform.position += deltaTime * playerInput.move * settings.playerMoveSpeed;

group.transform[index] = transform; // Write

 

ISharedComponentData

继承自ISharedComponentData的组件是共享组件,共享组件顾名思义,许多的实体会共用一个共享组件。EntityManager会将具有相同共享组件的实体放置在同一块中,相同共享组件除了组件,数据也相同。显然,共享组件特别适合作为网格和材质来使用,相同物体拥有相同的网格和材质,这样可以节省大量的资源。

注意:过度使用共享组件,可能导致块利用率低下。此外,如果从实体中添加或删除共享组件,修改共享组件的值,都会导致EntityManager将实体移动到其他块。

关于共享组件的重要说明:

  • ECS将具有相同共享组件的实体分类并存储在一个块中,但并没有和共享组件存放在一起,因此在实体中,共享组件的内存开销是0,但并不意味着共享组件不存在。
  • 可以使用EntityQuery对具有相同组件的实体进行遍历,也可以使用EntityQuery.SetFilter对具有特定值的共享组件的实体进行迭代,因为这些实体存放在一个块中,因此开销很低。
  • You can use EntityManager.GetAllUniqueSharedComponents to retrieve all unique SharedComponentData that is added to any alive entities.(你可以用EntityManager.GetAllUniqueSharedComponents来获得所有添加了共享组件的实体。ps:大概这样翻译?
  • 共享组件自动开启引用计数。
  • 共享组件应该很少被修改,如果要修改共享组件的值,可以使用memcpy()将该实体的所有内容复制到另一个块中。

 

ISystemStateComponentData

系统状态组件可以用来跟踪系统内部的资源,并根据需要创建资源和销毁,而不依赖各种回调。

系统状态组件和通用组件类似,但是在实体销毁的时候ECS不会删除系统状态组件实体,这使得系统可以根据未删除的实体去回收与该实体绑定的资源。

何时使用系统状态组件

当系统可能需要保持基于内部组件的状态,例如分配资源时。系统可以将状态进行管理,当状态变化时,添加或删除组件。

 

IBufferElementData

动态缓冲区组件将类似数组的数据与实体相关联,动态缓冲区可以容纳可变数量的元素,并可以自动调整大小。

要创建动态缓冲区,首先声明一个继承IBufferElementData的结构体,并在该结构体中定义存储的元素。

public struct IntBufferElement : IBufferElementData
{
    public int Value;
}

要向动态缓冲区中添加组件有两种方法

  • 使用EntityManager.AddBuffer()
EntityManager.AddBuffer<MyBufferElement>(entity);
  • 使用原型
Entity e = EntityManager.CreateEntity(typeof(MyBufferElement));

 

ISharedSystemStateComponentData

共享系统状态组件,可以看成是共享组件和系统状态组件的结合。

 

 

参考:https://docs.unity3d.com/Packages/com.unity.entities@0.11/manual/ecs_components.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值