前言
此示例演示了使用预制件游戏对象生成实体和组件的不同方法。与前面的示例一样,场景生成了成对的旋转立方体的“字段”。
它显示了什么?
在前面的示例中,实体的生成方式有两个主要区别:
- 在此示例中,预制件游戏对象由
SpawnerAuthoring_FromEntity 的MonoBehaviour转换为实体表示形式,采用其“转换游戏对象实体”方法。 - 该示例使用作业系统来生成实体,而不是使用MonoBehaviour中的 Start() 方法。
生成实体
组件数据可以具有对其他实体的引用。在本例中,我们有一个对实体预制件的引用。与游戏对象类似,在实例化和销毁预制件时,整个预制件将作为一个组进行克隆或删除。 这样,您就可以使用系统和组件数据编写所有运行时代码。 SpawnerSystem_FromEntity 查找所有Spawner_FromEntity 组件。 当它找到一个时,系统实例化网格中的预制件,然后销毁生成器实体(因此它只生成一组给定的实体一次)。 SpawnerSystem_FromEntity 使用实体Entities.ForEach ,它与前面示例中演示的非常相似。不同之处在于,此实体对象(以及查询中的实体索引)提供给您的 lambda。实体对象是必需的,以便系统可以在处理生成器实体后将其销毁。 目前,批量创建大量实体的最有效方法是使用EntityManager.Instanceiate() 批量实例化预制件的所有副本,然后使用并行作业提供每个实例的初始组件值。
项目
场景布置
代码编写
创建三个脚本 Spawner_FromEntity.cs
using Unity.Entities;
public struct Spawner_FromEntity : IComponentData
{
public int CountX;
public int CountY;
public Entity Prefab;
}
SpawnerAuthoring_FromEntity.cs
using System.Collections.Generic;
using Unity.Entities;
using UnityEngine;
[AddComponentMenu("DOTS Samples/SpawnFromEntity/Spawner")]
[ConverterVersion("joe", 1)]
public class SpawnerAuthoring_FromEntity : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
{
public GameObject Prefab;
public int CountX;
public int CountY;
public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
{
referencedPrefabs.Add(Prefab);
}
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
var spawnerData = new Spawner_FromEntity
{
Prefab = conversionSystem.GetPrimaryEntity(Prefab),
CountX = CountX,
CountY = CountY
};
dstManager.AddComponentData(entity, spawnerData);
}
}
SpawnerSystem_FromEntity.cs
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Entities.CodeGeneratedJobForEach;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
[UpdateInGroup(typeof(SimulationSystemGroup))]
public partial class SpawnerSystem_FromEntity : SystemBase
{
[BurstCompile]
struct SetSpawnedTranslation : IJobParallelFor
{
[NativeDisableParallelForRestriction]
public ComponentDataFromEntity<Translation> TranslationFromEntity;
public NativeArray<Entity> Entities;
public float4x4 LocalToWorld;
public int Stride;
public void Execute(int i)
{
var entity = Entities[i];
var y = i / Stride;
var x = i - (y * Stride);
TranslationFromEntity[entity] = new Translation()
{
Value = math.transform(LocalToWorld, new float3(x * 1.3F, noise.cnoise(new float2(x, y) * 0.21F) * 2, y * 1.3F))
};
}
}
protected override void OnUpdate()
{
Entities.WithStructuralChanges().ForEach((Entity entity, int entityInQueryIndex,
in Spawner_FromEntity spawnerFromEntity, in LocalToWorld spawnerLocalToWorld) =>
{
Dependency.Complete();
var spawnedCount = spawnerFromEntity.CountX * spawnerFromEntity.CountY;
var spawnedEntities =
new NativeArray<Entity>(spawnedCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
EntityManager.Instantiate(spawnerFromEntity.Prefab, spawnedEntities);
EntityManager.DestroyEntity(entity);
var translationFromEntity = GetComponentDataFromEntity<Translation>();
var setSpawnedTranslationJob = new SetSpawnedTranslation
{
TranslationFromEntity = translationFromEntity,
Entities = spawnedEntities,
LocalToWorld = spawnerLocalToWorld.Value,
Stride = spawnerFromEntity.CountX
};
Dependency = setSpawnedTranslationJob.Schedule(spawnedCount, 64, Dependency);
Dependency = spawnedEntities.Dispose(Dependency);
}).Run();
}
}
添加并设置脚本
总结
public class SpawnerAuthoring_FromEntity : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
{
public GameObject Prefab;
public int CountX;
public int CountY;
public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
{
referencedPrefabs.Add(Prefab);
}
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
var spawnerData = new Spawner_FromEntity
{
Prefab = conversionSystem.GetPrimaryEntity(Prefab),
CountX = CountX,
CountY = CountY
};
dstManager.AddComponentData(entity, spawnerData);
}
}
运行效果
|