首页 > 解决方案 > 如何将实体传递给作业以添加组件?

问题描述

编辑:见下面我的编辑)

为了在使用 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:NativeArray MyJob.Group.Entities 必须在作业 MySystem:MyJob 中标记为 [ReadOnly],因为容器本身标记为只读。

但是,如果我确实将其更改为[ReadOnly],它会抱怨我在到达该行时对其进行了编辑CommandBuffer.AddComponent

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

是否有另一种方法可以将EntityArray(或向 index 的实体添加组件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 未在 IJobParallelFor 作业中声明为 [ReadOnly]。容器不支持并行写入。请使用更合适的容器类型。

因此,为什么我把它ReadOnly放在首位。

标签: c#unity3djobsentity-component-system

解决方案


我找到了一种方法,但我不确定它是否安全,或者是否可以这样做,但是:

 // 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自己使用还是继承它。(我真的不知道有什么区别)


推荐阅读