はじめに
DOTS以前のUnityでは、
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です。