Prefabs in baking
制作预制体
首先我们要制作一个预制体。
预制体有两个组件需求
- 有一个预制体的标记,让方便我们去查询这个entity是不是一个预制体
- LinkedEntityGroup 缓冲区,将预制件中的所有子级存储在平面列表中,目的是为了快速生成一个完整的组实体,而不是只生成一个父物体
如果不添加预制体的标记,后果是你无法找到自己生成的预制体,如果不添加 LinkedEntityGroup(LinkedEntityGroupAuthoring)后果是你实例化的时候不会生成子物体,只生成父物体
生成预制体
预制体准备好了,我们要把预制体生成的entity保存起来。
保存也有两种方式
- 直接作为entity保存
public struct PrefabComponent:IComponentData
{
public Entity _entity;
}
public class PrefabAuthing : MonoBehaviour
{
public GameObject BakerObject;
}
public partial class PrefabBake :Baker<PrefabAuthing>
{
public override void Bake(PrefabAuthing authoring)
{
Entity entity = GetEntity(TransformUsageFlags.Dynamic);
Entity prefabEntity = GetEntity(authoring.BakerObject, TransformUsageFlags.Dynamic);
PrefabComponent prefabComponent = new PrefabComponent();
prefabComponent._entity = prefabEntity;
AddComponent(entity, prefabComponent);
}
}
- 作为EntityPrefabReference 进行保存
public struct PrefabComponent:IComponentData
{
public EntityPrefabReference _entity;
}
public class PrefabAuthing : MonoBehaviour
{
public GameObject BakerObject;
}
public partial class PrefabBake :Baker<PrefabAuthing>
{
public override void Bake(PrefabAuthing authoring)
{
Entity entity = GetEntity(TransformUsageFlags.Dynamic);
PrefabComponent prefabComponent = new PrefabComponent();
prefabComponent._entity = new EntityPrefabReference(authoring.BakerObject);
AddComponent(entity, prefabComponent);
}
}
EntityPrefabReference的效果将对应的Entity烘焙成独立的文件,该文件可以在使用预制件之前在运行时加载,这样他就可以在多个SubScene中使用了。这里要注意,PrefabAuthing 里面存的一定要是预制体,而不是普通的GameObject.如果存储普通的GameObject 会在生成的时候报错。
预制体使用并生成
这个生成同样是在运行是生效的,所以我们需要使用到System
- 对于生成的是Entity的预制体
public partial class InstancePrefabSystem : SystemBase
{
protected override void OnUpdate()
{
var ecb = new EntityCommandBuffer(Allocator.Temp);
// Get all Entities that have the component with the Entity reference
foreach (var prefab in SystemAPI.Query<RefRO<PrefabComponent>>())
{
//Instantiate the prefab Entity
var instance = ecb.Instantiate(prefab.ValueRO._entity);
//到这里就已经生成完毕了
// Note: the returned instance is only relevant when used in the ECB
// as the entity is not created in the EntityManager until ECB.Playback
MoveComponent moveComponent = new MoveComponent();
moveComponent.Speed = 5;
ecb.AddComponent<MoveComponent>(instance,moveComponent);
}
ecb.Playback(EntityManager);
ecb.Dispose();
}
}
- 对于生成EntityPrefabReference的方法
首先我们要获取到 EntityPrefabReference 对应的Entity
protected override void OnUpdate()
{
var ecb = new EntityCommandBuffer(Allocator.Temp);
foreach (var (component, entity) in SystemAPI.Query<RefRO<PrefabComponent>>().WithEntityAccess().WithNone<PrefabLoadResult>())
{
if (!EntityManager.HasComponent<RequestEntityPrefabLoaded>(entity))
{
RequestEntityPrefabLoaded load = new RequestEntityPrefabLoaded() { Prefab = component.ValueRO._entity };
ecb.AddComponent<RequestEntityPrefabLoaded>(entity,load);
}
}
ecb.Playback(EntityManager);
ecb.Dispose();
}
这里我们借助了 RequestEntityPrefabLoaded 这个组件,这个组件是自动去加载 EntityPrefabReference 所对应的 Entity的,而加载好的entity 则会存储在 自动添加的 PrefabLoadResult 组件里的 PrefabRoot中
接下来,我们对 PrefabLoadResult 直接做和entity相同的操作就行了
(我尝试根据示例中在OnStartRunning进行加载,失败了,退而求其次,选择在OnUpdate中加载)
生成预制体获取和删除
public partial class DestoryprefabSystem : SystemBase
{
protected override void OnUpdate()
{
//var prefabQuery = SystemAPI.QueryBuilder().WithAll<BakedEntity>().WithOptions(EntityQueryOptions.IncludePrefab).Build();
var ecb = new EntityCommandBuffer(Allocator.Temp);
//在这里进行获取
// Get all Entities that have the component with the Entity reference
foreach (var (component, entity) in
SystemAPI.Query<RefRO<LocalTransform>>().WithEntityAccess())
{
// Instantiate the prefab Entity
if (component.ValueRO.Position.x > 20)
{
//这一步是删除
ecb.DestroyEntity(entity);
}
}
ecb.Playback(EntityManager);
ecb.Dispose();
}
}
这样我们就能查找到对应的Entity和删除了
EntityCommandBuffer
我们在做这些的时候用到了 EntityCommandBuffer 这个类,这个类是干啥的呢
EntityCommandBuffer 是用于块和数据的内存分配器,他负责去分配各种数据所对应的内存,
而Allocator.Temp 是指的临时分配内存,我们所实例化出来的Entity需要临时存储在这个类型的内存中。
而 Playback 是为了回放所有的操作,并将这些操作记录在EntityManager中执行(在场景中执行),
执行后,上面的数据才会放置到对应的EntityManager和场景中。
Dispose 则是将过程中产生的内存释放掉(比如生成的Entity).
这样我们就完成了预制体的加载,查询和删除了。