Entity Command Buffer使用
前言
直接的创建,销毁Entity,以及对Entity的结构进行更改(比如增加删除Component)都要通过EntityManager等接口来实现。
在Job中,只能实现对Entity的Component组件进行数据修改的功能。
我们对Entity的修改只能在主线程上进行。
在Job中需要通过Entity Command Buffer实现对Entity修改操作的记录;然后回到主线程进行统一操作。
一、Entity Command Buffer是什么?
在主线程上创建一个ECB对象,传递到Job中,然后在Job中进行对应的操作记录后,在主线程进行回放操作。
ECB可以看做类似在Job中使用的EntityManager,但是因为实际操作还是在主线程,所以有一定的规则进行约束。
二、Entity Command Buffer创建
ECB对象的创建,需要在Job中使用时,需要传入Allocator.TempJob,或Allocator.Persistent。因为它的生命周期不只是当前函数或者当前帧,是需要传入到Job中使用的。
EntityCommandBuffer ecb = new EntityCommandBuffer(Allocator.TempJob);
ECB如果要在多个并行的Job中使用,需要转换成ParalleWriter,再传入到Job中使用。
三、Entity Command Buffer使用
ECB的playBack方法需要在主线程调用(一般在System中),所以要保证使用ECB去记录修改的Job需要在调用playBack方法之前调用完毕。
在playBack之后,类似NativeArrary一样,需要手动去销毁。所以一般的使用流程:
- 依赖的Job的handle上调用Complete让主线程等待完成
- 调用ECB.PlayBack,去回放操作
- 调用ECB.Dispose,去销毁ECB内存
利用JOB去创建Entity时,所以Job无法继承IJobEntity以及IJobChunk来实现。需要利用IJob,IJobFor,IJobParallelFor这些基础Job接口来实现多线程。
注意点:
1.在Job中使用ECB时,无法对创建出的临时Entity进行SetComponent操作,因为Job创建的Entity只是临时的,实际回放时,才会创建真正的Entity。只能给Entity进行AddComponent操作。需要用其他的System在创建完这些Entity的System之后,再来操作这些Entity的Component来实现设置数据。
2.也不能在ECB回放的主线程上,对拿到的Entity集合进行操作。
3.ParalleWriter在写入时为了保证回放的顺序,内部使用了EntityIndexInQuery
4.最好每个单独的JOB使用独立的ECB,避免出现各类问题。
5.ECB的PlayBack方法,最好只调用一次。多次调用可能会出问题,如果要多次调用可以参考PlaybackPolicy.MutiPlayback选项。
四、Entity Command Buffer System
可以自定义Entity Command Buffer System,来使用ECB,在这个System中创建的ECB放到Job中使用时,需要注意依赖问题,同时不需要手动Playback,以及手动dispse ECB。
DOTS中会默认创建一些ECB System来提供我们使用,一般情况,不需要自定义ECB System。
可以通过代码获取这些阶段的ECB来依赖这些默认ECBSystem的回放流程,完成我们的回放操作。比如BeginInitializationEntityCommandBufferSystem中的,它会在下一帧进行回放操作。这样我们就不需要自己去管理回放了。
总结
Entity Command Buffer主要用于在Job中创建,销毁Entity,对Entity的Component的增加,删除。但无法实现对创建的Entity来setComponent。