ECS框架文档翻译十五 Using Component​System and For​Each

以下文档均来源于ECS官网:

https://docs.unity3d.com/Packages/com.unity.entities@0.0/manual/ecs_entities.html

使用ComponentSystem

您可以使用ComponentSystem来处理数据。ComponentSystem的方法在主线程上运行,因此无法利用CPU的多核,一般被使用在以下情况中:

  • 调试或探索性开发 - 如果代码在主线程上运行,有时更容易发现发生了什么。例如,您可以输出调试文本或绘制​​调试图形。
  • 当系统需要访问,或者交互那些只能在主线程上运行的API接口时 - 这可以帮助您逐步将游戏系统转换为ECS模式,而不必从一开始就重写所有内容。
  • 系统执行的工作量很小,甚至少于创建和调度作业的微小开销。

重要提示: 进行结构级的更改会强制完成所有作业。 此事件称为同步点(sync point),它可能会导致性能下降,因为系统在等待同步点时无法利用所有可用的CPU内核。 在ComponentSystem中,您应该使用后更新命令缓存(PostUpdateCommands)。 同步点仍然会出现,但所有结构变化都是在一个批次中发生的,因此带来的影响略小。为了获得最大效率,请使用JobComponentSystem和实体命令缓存。 在创建大量实体时,您还可以使用一个单独的World来创建实体,然后将这些实体转移到主游戏World。

使用 ForEach 委托来遍历

ComponentSystem提供了Entities.ForEach函数,该函数简化了遍历实体组的工作。 在System的OnUpdate()函数中调用ForEach,传入一个lambda函数并将相关组件作为其参数,然后在函数体内执行你所需要的操作。

以下示例来自HelloCube中的ForEach示例,为具有RotationQuaternion和RotationSpeed组件的所有实体设置旋转动画:

public class RotationSpeedSystem : ComponentSystem
{
   protected override void OnUpdate()
   {
       Entities.ForEach( (ref RotationSpeed rotationSpeed, ref RotationQuaternion rotation) =>
       {
           var deltaTime = Time.deltaTime;
           rotation.Value = math.mul(math.normalize(rotation.Value),
               quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * deltaTime));
       });
   }

您可以将ForEach lambda函数与最多六种组件类型一起使用。

如果需要对现有实体进行结构级更改,可以将实体组件添加到lambda函数参数中,并使用它将命令添加到ComponentSystem的PostUpdateCommands缓存。(如果系统允许在lambda函数内部立刻进行结构级的更改,则可能会更改正在遍历中的数组中的数据布局,从而导致错误或其他未定义的行为)

For example, if you wanted to remove the RotationSpeed component form any entities whose rotation speed is currently zero, you could alter your ForEach function as follows:

例如,如果当某个实体的RotationSpeed组件的rotation speed为0时,需要移除此RotationSpeed组件,你可以将ForEach函数改成以下形式:

Entities.ForEach( (Entity entity, ref RotationSpeed rotationSpeed, ref RotationQuaternion rotation) =>
{
   var __deltaTime __= Time.deltaTime;
   rotation.Value = math.mul(math.normalize(rotation.Value),
       quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * __deltaTime__));

   if(math.abs(rotationSpeed.RadiansPerSecond) <= float.Epsilon) //Speed effectively zero
       PostUpdateCommands.RemoveComponent(entity, typeof(RotationSpeed));               
});

当OnUpdate()函数完成以后,系统会在后更新命令缓存中执行相应的命令。

流式查询(Fluent Queries)

您可以使用流式查询( fluent-style )来约束ForEach lambda表达式,使其仅在满足某些约束的特定实体集上执行。 这些查询可以使用any、all或none约束来筛选组件,从而筛选出那些满足条件的实体。多个约束条件可以串联在一起,对于C#的LINQ系统的使用者来说应该非常熟悉。

请注意,作为参数传递给ForEach lambda函数的任何组件,都会自动包含在WithAll集中,并且不能再显式地包含在查询的WithAll,WithAny或WithNone部分中。

WithAll 约束允许您指定目标实体必须包含的组件集{译者注:不限于}。 例如,使用以下查询,ComponentSystem为具有“Rotation”和“Scale”组件的所有实体执行lambda函数:

Entities.WithAll<Rotation, Scale>().ForEach( (Entity e) =>
{
    // do stuff
});

将WithAll用于那些存在于实体上,但不需要读取或写入的组件(将要访问的组件作为ForEach lambda函数的参数)。 例如:

Entities.WithAll<SpinningTag>().ForEach( (Entity e, ref Rotation r) =>
{
    // do stuff
});

WithAny 约束允许你指定目标实体至少需要包含的组件集。ComponentSystem将在这样的实体上运行以下lambda函数,它们包含了Rotation和Scale组件,且包含RenderDataA或RenderDataB组件(或者同时包含二者):

Entities.WithAll<Rotation, Scale>().WithAny<RenderDataA, RenderDataB>().ForEach( (Entity e) =>
{
    // do stuff
});

请注意,你无法知道具体的实体中存在WithAny集合中的哪些组件。 如果需要根据存在哪些组件来区别对待实体,则必须为每种情况创建特定的查询,或者将JobComponentSystem与IJobChunk一起使用。

WithNone 约束允许指定目标实体不允许包含的组件集。 ComponentSystem将为没有Rotation组件的所有实体执行以下lambda函数:

Entities.WithNone<Rotation>().ForEach( (Entity e) =>
{
    // do stuff
});

此外,您可以指定WithAnyReadOnly 和WithAllReadOnly 来筛选具有相应组件的实体,然要要确保这些组件必须是以只读方式进行查询。 也就是说,这将确保组件被访问时没有被标记为已写入,且其块ID会发生改变{译者注:块中的每一类组件都对应一个版本ID,当这类组件发生变化时,或者仅仅是被可以写入的Job访问时,此组件对应的版本ID就会发生变化}。

可选项

你还可以指定以下一系列的可选项来查询:

可选项描述
Default无指定选项
IncludePrefab本次查询不会隐式排除那些拥有特殊预制体标签组件的实体
IncludeDisabled本次查询不会隐式排除那些拥有特殊禁用标记组件的实体
FilterWriteGroup本次查询需要考虑组件中设置的WriteGroupAttribute 属性

ComponentSystem 将会为所有没有Rotation组件的实体执行以下lambda函数,包含那些存在Disabled组件的实体:

Entities.WithNone<Rotation>().With(EntityQueryOptions.IncludeDisabled).ForEach( (Entity e) =>
{
    // do stuff
});
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值