Entities - 遍历与查询

Unity DOTS实体查询与遍历

DOTS 程序的三大主要工作:

  • 设计与组织数据
  • 遍历与查找数据
  • 修改与更新数据

【Component 类型】中说过可以将 Component 按照数据访问类型进行划分,分别是 Entity,Chunk,Element,数据与查询中也是如此

1、遍历查询 Entity 数据的 5 种方式

  • SystemAPI.Query + ForEach

SystemAPI.Query 用于在合集中过滤出我们需要的子集,然后通过 ForEach 遍历,Query中可以有七种重载查询类型:

但是Query 有两个使用限制:

(1)DynamicBuffer 只读限制:默认为读写访问,如果希望只读,必须自己实现

(2)不能存储 SystemAPI.Query<T>(),然后在一个或多个 foreach 语句中使用它(这是因为SytemAPI.Query 的模板类型是要在编译时确定并生成代码的,也就是说不能用分支语句去控制 SystemAPI.Query 语句的查询结果)

(3)只能在主线程运行

  • IJobEntity

这是一种隐式查询后遍历的一种方式

(1)与Entities.ForEach功能类似,为每个Entity调用一次Execute
(2)可在多个System中重用
(3)底层是IJobChunk实现的
(4)查询方式WithAll、WithAny、WithNone、WithChangeFilter、WithOptions
(5)可以通过 【EntityIndexInQuery】 属性来在 Execute 方法中获取 Entity 遍历查询中的索引

[BurstCompile]
public partial struct CopyPostion : IJobEntity
{
    public NativeArray<float3> copyPositions;
    public void Execute([EntityIndexInQuery] int entityIndexInQuery, in LocalTransform localTransform)
    {
        copyPositions[entityIndexInQuery] = localTransform.Position;
    }
}
  •  IJobChunk

(1)遍历ArcheType Chunk
(2)为每个Chunk调用一次Execute
(3)一般用在不需要遍历每个Chunk中Entity的情况或者对Chunk内的Entity执行多次遍历或以不寻常顺序遍历的情况
(4)useEnabledMask与ChunkEnableMask来辅助过滤Enableable Component未激活的Entity

注意第(4)点,IJobEntity 和 Entities.ForEach 遍历时会自动跳过与其 EnableableComponent 状态不匹配的 Entity,但是 IJobChunk 不会

  • Entities.ForEach

(1)只用于继承SystemBase创建的System

(2)定义是一个Lambda表达式

(3)有太多的使用限制

  • Manually

(1)entityManager.GetAllEntities()

(2)entityManager.GetAllChunks()

再通过 Foreach 方法去遍历上面两个接口得到的合集,设置限制条件查询。这种方法使用限制最小,但从性能角度来说是不划算的

举个例子:

【Entity的创建模式】中的旋转方块的例子为基础,这次设置三种不同颜色的方块,并且每个颜色的方块写一个旋转 System,可以发现方块旋转的非常快,通过 Systems 可以看到,每个 System 处理的 Entity 数量都是 9 个,相当于每个 System 都在对每个颜色的方块进行旋转,每一帧进行了三次旋转处理。

这个时候为了区分每个颜色的方块,就可以用 Tag Component 来分类每个颜色的方块,Tag Component 不包含数据,可以在 Archetype 窗口中看到这些 Component 占了 0 字节,以其中一个为例:

struct RedCubeTag:IComponentData
{
}
public class RedCubeTagAuthoring : MonoBehaviour
{
    public class Baker:Baker<RedCubeTagAuthoring>
    {
        public override void Bake(RedCubeTagAuthoring authoring)
        {
            var redCube =new RedCubeTag();
            AddComponent(redCube);
        }
    }
}

然后更新 System 中的 Update

[BurstCompile]
public void OnUpdate(ref SystemState state)
{
    float deltaTime = SystemAPI.Time.DeltaTime;
    foreach (var (transform, speed, tag)) in SystemAPI.Query<RefRW<LocalTransform>, RefRO<RotateSpeedComponent>, RefRO<RedCubeTag>>())
    {
        transform.ValueRW = transform.ValueRO.RotateY(speed.ValueRO.rotateSpeed * deltaTime);
    }
}

还有一种情况,如果要查询所有 Component A 与 C 的 chunk

那么通过 SystemAPI.Query<A,C>(),包含 A,B,C的 chunk 也会被获取,如果要获取只包含 A,C组件的 chunk,那么可以通过创建自定义的 query,并且可以通过多线程处理

new EntityQueryBuilder(Allocator.Temp) .WithAll<A>0 .WithAll<C>() .WithNone<B>() .Build(this).

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值