TD 敵のスポーン機能を実装 2/2：ObjectPoolを使って実装

# 概要
今回はデザインパターンのObjectPoolを使って、敵のスポーンを管理します。
ObjectPoolを使うことでゲームオブジェクトの生成、削除する回数が少なくなりパフォーマンスが向上します。
以下gifのような動きを実現します。
１秒毎にPool配下の子オブジェクトが活性化されています。ゲーム的には１秒毎に敵がスポーンされているという意味です。

![Spwan1111.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/f4c50847-9995-d2d9-9077-52f2fee83593.gif)




# 開発環境

IDE:Rider
Unity:2020.3.42(LTS)
OS:Windows10

# 実装の方針
従来：Objectの有無（CreateInstanceとDestor）で敵のスポーンを管理
今回：あらかじめ生成されるオブジェクトを全て生成し、GameObject.setActive(true or false)で敵のスポーンの有無を表現する。



# コード

```diff_c_sharp:ObjectPooler.cs
using System.Collections.Generic;
using UnityEngine;

public class ObjectPooler : MonoBehaviour
{
    [SerializeField] private GameObject prefab;
    [SerializeField] private int poolSize;
    
    private List<GameObject> _pool;
    private GameObject _poolContainer;

    private void Awake()
    {
        _pool = new List<GameObject>();
        _poolContainer = new GameObject($"Pool - {prefab.name}");
        CreatePooler();
    }

    private void CreatePooler()
    {
        for (int i = 0; i < poolSize; i++)
        {
            _pool.Add(CreateInstance());
        }
    }
    
    private GameObject CreateInstance()
    {
        GameObject newInstance = Instantiate(prefab);
        newInstance.transform.SetParent(_poolContainer.transform);
        newInstance.SetActive(false);
        return newInstance;
    }

    // 
    public GameObject GetInstanceFromPool()
    {
        for (int i = 0; i < _pool.Count; i++)
        {
            if (!_pool[i].activeInHierarchy)
            {
                return _pool[i];
            }
        }
        // poolの数がいっぱいの場合は空のGameObjectを返す。
        return CreateInstance();
    }
}
```


```diff_c_sharp:Spawner.cs
using System;
using UnityEngine;


    public class Spawner : MonoBehaviour
    {
-        [SerializeField] private GameObject testGO;
        [SerializeField]  private  int enemyCount = 10;
        // Btw = Between
        [SerializeField] private float delayBtwSpawns;

        private int _enemiesSpawned;
        private float _spawnTimer;
+        private ObjectPooler _objectPooler;

        private void Start()
        {
            _objectPooler = GetComponent<ObjectPooler>();
        }

        private void Update()
        {
            _spawnTimer -= Time.deltaTime;
            if (_spawnTimer < 0)
            {
                _spawnTimer = delayBtwSpawns;
                if (_enemiesSpawned < enemyCount)
                {
                    SpawnEnemy();
                    _enemiesSpawned++;
                }
            }
        }
        
        private void SpawnEnemy()
        {
+            GameObject newInstance = _objectPooler.GetInstanceFromPool();
+            newInstance.SetActive(true);
        }
        
    }


```


# 参考
SetActive

https://docs.unity3d.com/ja/560/ScriptReference/GameObject.SetActive.html

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/833941c0-b630-3dec-321b-c72e25af397e.png)

$ を使う文字列補間

https://learn.microsoft.com/ja-jp/dotnet/csharp/language-reference/tokens/interpolated

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/e92f7b7d-adf4-97a8-dc50-297cef40045c.png)

UnityでObjectPoolのクラスが実装されている模様

https://docs.unity3d.com/ScriptReference/Pool.ObjectPool_1.html

Section3 9 ObjectPooler

https://www.udemy.com/course/learn-how-to-create-a-2d-tower-defense-game-in-unity-2020/learn/lecture/22896394#content

github コミット分

https://github.com/RYA234/2DTowerDeffenceMyLearning/commit/846ca44d60459421001d3ee55ce018c33edf35f7