EntitiesSample_6. Reparenting
该示例的关键点有两个,一个是 Parent,Child组件的使用,这两个组件是内置的,标识对象之间嵌套的引用,第二个关键点是 ecb.Playback(state.EntityManager)的使用,在使用EntityCommandBuffer对实体惊醒操作之后,使用playback接口保证数据的同步,EntityCommandBuffer命令执行在各个job中,无法确定执行的顺序和时间,就像是Mono托管编程中的协程,通过回调函数与主线程数据同步
public partial struct ReparentingSystem : ISystem
{
bool attached;
float timer;
const float interval = 0.7f;
[BurstCompile]
public void OnCreate(ref SystemState state)
{
timer = interval;
attached = true;
state.RequireForUpdate<ExecuteReparenting>();
state.RequireForUpdate<RotationSpeed>();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
//时间计时 interval,interval秒设置一次
timer -= SystemAPI.Time.DeltaTime;
if (timer > 0)
{
return;
}
timer = interval;
//获取场景中RotationSpeed挂载这个脚本的实体
var rotatorEntity = SystemAPI.GetSingletonEntity<RotationSpeed>();
//创建ecb命令,使用该命令对实体世界操作,这个命令可以在各个job上调度
var ecb = new EntityCommandBuffer(Allocator.Temp);
if (attached)
{
//获取挂载RotationSpeed脚本的子实体,如果一个实体有子实体,
//会自动被挂载上Child组件,引用的所有的子实体,Child继承自IBufferElementData,就像mono中的getComponentsInChild
//子实体拥有一个Parent组件,引用的父级
DynamicBuffer<Child> children = SystemAPI.GetBuffer<Child>(rotatorEntity);
for (int i = 0; i < children.Length; i++)
{
// Using an ECB is the best option here because calling EntityManager.RemoveComponent()
// instead would invalidate the DynamicBuffer, meaning we'd have to re-retrieve
// the DynamicBuffer after every EntityManager.RemoveComponent() call.
使用ECB是最好的选择,因为调用EntityManager。移除组件()
//相反,会使DynamicBuffer无效,这意味着我们必须重新检索
//每个EntityManager之后的DynamicBuffer。RemoveComponent()调用。
ecb.RemoveComponent<Parent>(children[i].Value);
}
/* 这个是可以替代上面的循环,RemoveComponent可以传一个实体数组,
* 参数就是把 DynamicBuffer<Child> 先转化成 NativeArray<Child> 然后在转化成 NativeArray<Entity>
ecb.RemoveComponent<Parent>(children.AsNativeArray().Reinterpret<Entity>());
*/
}
else
{
//查找没有 RotationSpeed组件的实体,然后添加Parent组件
foreach (var (transform, entity) in
SystemAPI.Query<RefRO<LocalTransform>>()
.WithNone<RotationSpeed>()
.WithEntityAccess())
{
ecb.AddComponent(entity, new Parent { Value = rotatorEntity });
}
/* 替换上面的循环
var query = SystemAPI.QueryBuilder().WithAll<LocalTransform>().WithNone<RotationSpeed>().Build();
ecb.AddComponent(query, new Parent { Value = rotatorEntity });
*/
}
//ecb的操作结果传到管理器中
ecb.Playback(state.EntityManager);
attached = !attached;
}
}
其中有两个循环的简写
//删除数组中所有实体Parent组件
ecb.RemoveComponent<Parent>(children.AsNativeArray().Reinterpret<Entity>());
//创建一个查询,给这个查询结果添加 Parent组件
var query = SystemAPI.QueryBuilder().WithAll<LocalTransform>().WithNone<RotationSpeed>().Build();
ecb.AddComponent(query, new Parent { Value = rotatorEntity });