此示例演示了使用预制件游戏对象生成实体和组件的不同方法。与前面的示例一样,场景生成了成对的旋转立方体的“字段”。
在前面的示例中,实体的生成方式有两个主要区别:
SpawnerAuthoring_FromEntity
的MonoBehaviour转换为实体表示形式,采用其“转换游戏对象实体”方法。组件数据可以具有对其他实体的引用。在本例中,我们有一个对实体预制件的引用。与游戏对象类似,在实例化和销毁预制件时,整个预制件将作为一个组进行克隆或删除。
这样,您就可以使用系统和组件数据编写所有运行时代码。
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;
// ReSharper disable once InconsistentNaming
[AddComponentMenu("DOTS Samples/SpawnFromEntity/Spawner")]
[ConverterVersion("joe", 1)]
public class SpawnerAuthoring_FromEntity : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
{
public GameObject Prefab;
public int CountX;
public int CountY;
// Referenced prefabs have to be declared so that the conversion system knows about them ahead of time
// 必须声明引用的预制件,以便转换系统提前了解它们
public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
{
referencedPrefabs.Add(Prefab);
}
// Lets you convert the editor data representation to the entity optimal runtime representation
// 允许您将编辑器数据表示形式转换为实体最佳运行时表示形式
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
var spawnerData = new Spawner_FromEntity
{
// The referenced prefab will be converted due to DeclareReferencedPrefabs.
// 引用的预制件将由于声明引用预制件而被转换。
// So here we simply map the game object to an entity reference to that prefab.
// 因此,在这里,我们只需将游戏对象映射到对该预制件的实体引用。
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;
// Systems can schedule work to run on worker threads.
// 系统可以安排工作在工作线程上运行。
// However, creating and removing Entities can only be done on the main thread to prevent race conditions.
// 但是,创建和删除实体只能在主线程上完成,以防止出现争用情况。
// The system demonstrates an efficient way to batch-instantiate and apply initial transformations to a large
// number of entities.
// 该系统演示了一种对大量实体进行批量实例化和应用初始转换的有效方法。
// ReSharper disable once InconsistentNaming
[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;
// Referenced prefabs have to be declared so that the conversion system knows about them ahead of time
// 必须声明引用的预制件,以便转换系统提前了解它们
public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
{
referencedPrefabs.Add(Prefab);
}
// Lets you convert the editor data representation to the entity optimal runtime representation
// 允许您将编辑器数据表示形式转换为实体最佳运行时表示形式
public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
{
var spawnerData = new Spawner_FromEntity
{
// The referenced prefab will be converted due to DeclareReferencedPrefabs.
// 引用的预制件将由于声明引用预制件而被转换。
// So here we simply map the game object to an entity reference to that prefab.
// 因此,在这里,我们只需将游戏对象映射到对该预制件的实体引用。
Prefab = conversionSystem.GetPrimaryEntity(Prefab),
CountX = CountX,
CountY = CountY
};
dstManager.AddComponentData(entity, spawnerData);
}
}