EntityCommandBuffer解决了2个问题:
当你再Job中时,不可以访问EntityManager
当访问EntityManager时(比如,创建一个Entity)导致导致访问的Components数组失效,及EntityQuery对象失效。
Entity Command Buffer抽象允许我们将改变保存到队列(从Job或者主线程),然后在稍后在主线程中应用。有2中应用EntityCommandBuffer的方法:
ComponentSystem的子类PostUpdateCommands可以在主线程中执行。可以简单地调用方法来将改变队列化,当world执行完该系统的Update后,会立即应用它们。
例子:
PostUpdateCommands.CreateEntity(TwoStickBootstrap.BasicEnemyArchetype);
PostUpdateCommands.SetComponent(new Position2D{Value= spawnPosition});
PostUpdateCommands.SetComponent(new Heading2D{Value = new float2(0.0f,-10f)});
PostUpdateCommands.SetComponent(default(Enemy));
PostUpdateCommands.SetComponent(new Helath{Value=TwoStickBootstrap.Settings.enemyInitialHealth});
PostUpdateCommands.SetComponent(new EnemyShootState{Cooldown=0.5f});
PostUpdateCommands.SetComponent(new MoveSpeed(speed=TwoStickBootstrap.Setting.enemySpeed));
PostUpdateCommands.AddSharedComponent(TwoStickBootstrap.EnemyLook);
对Jobs来说,必须在主线程中从entity command buffer system请求EntityCommandBuffer,然后传递给jobs。当EntityCommandBufferSystem更新时,command buffer会在主线程中按照创建的顺序执行它们。
Entity Command Buffer Systems
默认World初始化时创建了3个system groups,用来初始化,模拟,显示,它们在每一帧顺序执行。在每个group中,有一个entity command buffer system,在groups内所有其它system执行前执行一次,并且在所有其它system执行完后再执行一次。我们建议使用已有的command buffer systems,而不是自己创建,这样可以最小化同步点数量(Command buffer system越多,Sync Points越多)。
Using EntityCommandBuffers from ParallelFor jobs
当在ParallelFor jobs中使用EntityCommandBuffer来执行EntityManager命令时,EntityCommandBuffer.Concurrent接口可以保证线程安全和执行的确定性。该方法需要一个额外的jobIndex作为参数,用来保证命令回放执行的顺序是确定的。JobIndex必须是每个job唯一的。为了提升效率,jobIndex应该是传递给IJobParallelFor.Execute()的自增的index值。除非你帧地了解它们的顺序关系,否则用Execute()的index 参数是最佳选择。使用其它的jobIndex即使正确执行了,也可能带来效率方面的其它问题。