PrefabからEntityを生成する方法メモ(Entities v0.8.0)

# はじめに

DOTS以前のUnityでは、

```cs

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の作成

```cs
using Unity.Entities;

/// <summary>
/// 生成するPrefabに対応するEntityの情報
/// </summary>
public struct SpawnerData : IComponentData
{
    public Entity PrefabEntity;
}
```

```cs
using Unity.Entities;

/// <summary>
/// Spawnerを識別するためのタグコンポーネント
/// </summary>
public struct Spawner : IComponentData
{
}

```

```cs

using Unity.Entities;

/// <summary>
/// Spawnをするタイミングを伝えるためのタグコンポーネント
/// </summary>
public struct SpawnTag : IComponentData
{
}
```

# Spawnerオブジェクトの作成
空のゲームオブジェクトを作成し、`ConvertToEntity`を付けます。

# SpawnerAuthoringの作成

```cs
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の作成

```cs
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です。