はじめに
DOTS以前のUnityでは、PrefabからGameObjectを生成したい時、
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SpawnPrefab : MonoBehaviour { [SerializeField] private GameObject prefab; private void Start () { Instantiate (prefab); } }
のようなスクリプトを作成し、何らかのオブジェクトにアタッチしておけば、実行時にPrefabからGameObjectが生成されていました。
これと同じことをHybrid ECSで行う工程をメモとして残しておきたいと思い、この記事を書きました。
環境
- Unity 2019.3.6f1
- Entities 0.8.0
- Unity Physics 0.2.5
- Hybrid Renderer 0.4.0
Prefabの準備
生成したいGameObjectにConvertToEntity
をアタッチし、必要に応じてAuthoring、PhysicsShape、PhysicsBody等をつけた後、Prefab化します。
(旧アーキテクチャのColliderがついている場合は消しておきましょう)
必要なComponentDataの作成
using Unity.Entities; /// <summary> /// 生成するPrefabに対応するEntityの情報 /// </summary> public struct SpawnerData : IComponentData { public Entity PrefabEntity; }
using Unity.Entities; /// <summary> /// Spawnerを識別するためのタグコンポーネント /// </summary> public struct Spawner : IComponentData { }
using Unity.Entities; /// <summary> /// Spawnをするタイミングを伝えるためのタグコンポーネント /// </summary> public struct SpawnTag : IComponentData { }
Spawnerオブジェクトの作成
空のゲームオブジェクトを作成し、ConvertToEntity
を付けます。
SpawnerAuthoringの作成
using System.Collections.Generic; using Unity.Entities; using UnityEngine; [DisallowMultipleComponent] [RequiresEntityConversion] public class SpawnerAuthoring : MonoBehaviour, IConvertGameObjectToEntity, IDeclareReferencedPrefabs { [SerializeField] private GameObject prefab; public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) { dstManager.AddComponentData(entity, new Spawner()); dstManager.AddComponentData(entity, new SpawnerData() { PrefabEntity = conversionSystem.GetPrimaryEntity(prefab) }); // 今回は簡単な例を考え、実行時にEntityを生成することにします。なのでここでSpawnTagをつけます dstManager.AddComponentData(entity, new SpawnTag()); } public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs) { referencedPrefabs.Add(prefab); } }
これをSpawnerオブジェクトにアタッチし、最初に作成したPrefabをエディタ上のPrefabフィールドに代入します。
SpawnSystemの作成
using Unity.Entities; /// <summary> /// Prefabを生成するSystem /// </summary> public class SpawnSystem : SystemBase { private EntityCommandBufferSystem _entityCommandBufferSystem; protected override void OnCreate() { _entityCommandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>(); } protected override void OnUpdate() { var concurrent = _entityCommandBufferSystem.CreateCommandBuffer().ToConcurrent(); Entities .WithBurst() .WithAll<SpawnTag, Spawner>() .ForEach( (Entity entity, int entityInQueryIndex, in SpawnerData spawnerData) => { concurrent.Instantiate(entityInQueryIndex, spawnerData.PrefabEntity); // Entityを2つ以上生成しないために、ここでSpawnTagを剥がします // これをしないと、毎フレームEntityが生成されてしまうので concurrent.RemoveComponent<SpawnTag>(entityInQueryIndex, entity); }).ScheduleParallel(); _entityCommandBufferSystem.AddJobHandleForProducer(Dependency); } }
これで実行時にPrefabからEntityが生成されます。
ここでは、実行時にEntityを生成する簡単な場合を考えましたが、好きなタイミングでEntityを生成したい場合は、そのタイミングでSpawnTag ComponentDataをSpawnerのEntityに付ければokです。