如何将实体传递给作业以添加组件?

How to pass Entities to a job to add Components?

(编辑: 请参阅下面我的编辑)

为了在使用 ECS 时减少样板代码,我将这段代码变成了:

之前:

public class MySystem : JobComponentSystem
{
    public struct Group
    {
       // A long list of different ComponentDataArray
       // Eg.
       public ComponentDataArray<Position> Positions;

       public int Length;
    }

    [Inject] private Group _Group;

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        MyJob job = new Job()
        {
           DeltaTime = Time.deltaTime,
           // That same long list of ComponentDataArray
        };
        return job.Schedule(_Group.Positions.Length, 64, inputDeps);
    }

    [BurstCompile]
    struct MyJob : IJobParallelFor
    {
        public float DeltaTime;
        // That same long list of ComponentDataArray AGAIN.

        public void Execute(int i)
        {
             // MyJob code
        }
    }
}

之后:

public class MySystem : JobComponentSystem
{
    public struct Group
    {
       // A long list of different ComponentDataArray
       // Eg.
       public ComponentDataArray<Position> Positions;

       public int Length;
    }

    [Inject] private Group _Group;

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        MyJob job = new Job()
        {
           DeltaTime = Time.deltaTime,
           Group = _Group
        };
        return job.Schedule(_Group.Positions.Length, 64, inputDeps);
    }

    [BurstCompile]
    struct MyJob : IJobParallelFor
    {
        public float DeltaTime;
        public Group Group;

        public void Execute(int i)
        {
             // MyJob code
        }
    }
}

在那之前,一切正常。直到我尝试在每个实体初始化后向它们添加一个组件。

public class MySystem: JobComponentSystem
{
    public struct Group
    {
        // A long list of different ComponentDataArray
        // Eg.
        public ComponentDataArray<Position> Positions;

        public SubtractiveComponent<Initialized> Initialized;

        public int Length;
        public EntityArray Entities;
    }

    [Inject] private Group _Group;

    public class EntityBarrier : BarrierSystem { }

    [Inject] private EntityBarrier _EntityBarrier;

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        MyJob job = new MyJob()
        {
            DeltaTime = Time.deltaTime,
            Group = _Group,
            CommandBuffer = _EntityBarrier.CreateCommandBuffer()
        };

        return job.Schedule(_Group.Positions.Length, 64, inputDeps);
    }

    [BurstCompile]
    struct MyJob : IJobParallelFor
    {
        public float DeltaTime;
        public Group Group;
        [ReadOnly] public EntityCommandBuffer CommandBuffer;

        public void Execute(int i)
        {
            CommandBuffer.AddComponent(Group.Entities[i], new Initialized());

            // MyJob code
        }
    }
}

它提高到哪个点:

InvalidOperationException: The NativeArray MyJob.Group.Entities must be marked [ReadOnly] in the job MySystem:MyJob, because the container itself is marked read only.

但是如果我将其更改为 [ReadOnly],它会在到达行 CommandBuffer.AddComponent.

时抱怨我编辑它

还提到哪个容器被标记为 ReadOnly

是否有另一种方法可以将 EntityArray(或将组件添加到索引 i 的实体)提供给作业而不需要示例 1 中看到的所有样板代码?

编辑: 如果我像这样手动喂它,仍然会抱怨:

public class MySystem : JobComponentSystem
{
    public struct Group
    {
       // A long list of different ComponentDataArray
       // Eg.
       public ComponentDataArray<Position> Positions;

       public SubtractiveComponent<Initialized> Initialized;

       public int Length;
       public EntityArray Entities;
    }

    [Inject] private Group _Group;

    public class EntityBarrier : BarrierSystem { }

    [Inject] private EntityBarrier _EntityBarrier;

    protected override JobHandle OnUpdate(JobHandle inputDeps)
    {
        MyJob job = new Job()
        {
           DeltaTime = Time.deltaTime,
           Entities = _Group.Entities,
           CommandBuffer = _EntityBarrier.CreateCommandBuffer(),
           // That same long list of ComponentDataArray
        };
        return job.Schedule(_Group.Positions.Length, 64, inputDeps);
    }

    [BurstCompile]
    struct MyJob : IJobParallelFor
    {
        public float DeltaTime;
        public EntityArray Entities;
        // That same long list of ComponentDataArray AGAIN.

        public void Execute(int i)
        {
             CommandBuffer.AddComponent(Entities[i], new Initialized());

             // MyJob code
        }
    }
}

这不是我们应该做的吗?在这里完成:https://forum.unity.com/threads/some-beginner-questions-about-pure-ecs.524700/#post-3449277

EDIT2: 我在他的代码中发现的唯一区别是

[ReadOnly]public EntityArray Entities;
public EntityCommandBuffer CommandBuffer;

并使用 EndFrameBarrier。我升级了代码但收到:

InvalidOperationException: MyJob.CommandBuffer is not declared [ReadOnly] in a IJobParallelFor job. The container does not support parallel writing. Please use a more suitable container type.

因此我把它放在第一位的原因是 ReadOnly

我找到了一种方法,但我不确定它是否安全或是否可行但是:

 // In your job
 [NativeDisableParallelForRestriction] public EntityCommandBuffer CommandBuffer;

在此处找到:https://forum.unity.com/threads/to-make-it-clear-do-i-have-a-start-function-on-ecs.523943/#post-3441718

无论您是使用 EndFrameBarrier 还是自己继承。 (我真的不知道有什么区别)