UnityECS学习04-Prefab与Spawner
使用 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
24namespace 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
35namespace HelloCube.Prefabs
{
public partial struct SpawnSystem : ISystem
{
private uint updateCounter;
[ ]
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate<Spawner>();
state.RequireForUpdate<Execute.Prefabs>();
}
[ ]
public void OnUpdate(ref SystemState state)
{
// 创建一个 query 来查找所有含有 RotationSpeed 的 entity
// query 会被缓冲到 source generation,因此不会每次 update 都创建
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 的中心即可。