使用 Prefab 创建 Entity
在之前的例子当中,都是使用场景中已存在的 GameObject 将其通过 Baking 后转换为 Entity。但是一般在实际开发的时候,都是封装好了许多的 Prefab,因此就有了这个需求。
改造
- 首先创建一个新的 SubScene 命名为 Spawner,并且将原来的 SubScene 的 Active 设置为
false
。注意要将其中的 Execute
复制过来。并且将我们的 RotatingCube
做成 Prefab。
- 接着在 Spawner 场景中创建一个空的 GameObject,挂载上我们的
SpawnerAuthoring.cs
。
- 再创建一个
SpawnSystem.cs
用于真正的生产逻辑。
- 在
Execute
上面勾选 Prefabs
以及任意一个实现了选择的 System 即可。
SpawnerAuthoring.cs
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| namespace HelloCube.Prefabs { public class SpawnerAuthoring : MonoBehaviour { public GameObject Prefab;
class Baker : Baker<SpawnerAuthoring> { public override void Bake(SpawnerAuthoring authoring) { var entity = GetEntity(TransformUsageFlags.None); AddComponent(entity, new Spawner { Prefab = GetEntity(authoring.Prefab, TransformUsageFlags.None) }); } } }
struct Spawner : IComponentData { public Entity Prefab; } }
|
此处对场景中每一个 entity,都加上了一个 Spawner
的组件,其中使用 GetEntity
去获取与之 GameObject 相关联的 Entity
SpawnSystem.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| namespace HelloCube.Prefabs { public partial struct SpawnSystem : ISystem { private uint updateCounter;
[BurstCompile] public void OnCreate(ref SystemState state) { state.RequireForUpdate<Spawner>(); state.RequireForUpdate<Execute.Prefabs>(); }
[BurstCompile] public void OnUpdate(ref SystemState state) { var spinningCubeQuery = SystemAPI.QueryBuilder().WithAll<RotationSpeed>().Build();
if (spinningCubeQuery.IsEmpty) { var prefab = SystemAPI.GetSingleton<Spawner>().Prefab; var instances = state.EntityManager.Instantiate(prefab, 500, Allocator.Temp); var random = Random.CreateFromIndex(updateCounter++); foreach (var entity in instances) { var transform = SystemAPI.GetComponentRW<LocalTransform>(entity); transform.ValueRW.Position = (random.NextFloat3() - new float3(0.5f, 0.0f, 0.5f)) * 20; } } } } }
|
- 此处的
updateCounter
相当于作为随机数种子,确保每一次生成的位置不一样。
- 接着通过
QueryBuilder()
返回的 SystemAPIQueryBuilder
查询场景中所有带有 RotationSpeed
组件的 entity。如果场景中没有,则进入下面的生成环节。
- 接着使用
GetSingleton
获取我们 Spawner 场景中的 Spawner Object(只能有一个实例)。就拿到了其上面放置的 RotationCube
预制体。
- 此处又使用
EntityManager
创造一个 NativeArray<Entity>
。其中的 Allocator.Temp
是分配效率最高的分配器,但是其只是应该临时数据,只存在于当前帧,帧结束后销毁。其中 NativeArray<T>
是可以在托管代码(c#)和本地代码(c++或c)之间高效传递和共享数据。不需要复制或者序列化操作。
- 最后再偏移一下生成的 entity 的中心即可。