タワーデフェンスゲーム　Unity　敵の機能　5/10 Object Poolを作って複数の敵オブジェクトを出現する様に実装

# 概要
前回の続きです。

https://qiita.com/RYA234/items/5d51902ac84f718aaa7f


今回は、複数敵が出現するように実装します。
ObjectPoolerを使います。

以下GIF画像は、再生時に敵が複数生成されている様子です。
![111111.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/67c557f7-df12-5e49-cab9-997c7e2d4c72.gif)

2Wave以降　最終地点に直行してますが次回改善します。
次へ

https://qiita.com/RYA234/items/f4af52f2bfa8538bf6b1

# 開発環境
IDE:Rider
Unity:2020.3.42(LTS)
OS:Windows10

# UnityEditorの画像
## Enemyプレハブの設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/890507b9-39a1-9900-c4b4-75000cd900d6.png)


## Spawnerオブジェクト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/9000cbb3-aa1d-ac9a-724e-6ff42963dd83.png)




# 実装のポイント
Enemyクラス上でWaypointをSpawnerクラスから参照できるようにします。
理由としては、Enemyクラスがアタッチされているオブジェクトをプレファブ化するとWaypointに参照できなくなるからです。

対処方法としてはSpawnerクラスで、Enemyのプレファブを生成する際にWaypointクラスを渡すようにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/3da01c95-a9ed-6f8c-41bd-770986ae16a9.png)


# コード部分

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

public class Enemy : MonoBehaviour
{
    public static Action OnEndReached;
    
    [SerializeField] private float moveSpeed = 3f;
-    [SerializeField] private Waypoint waypoint;
+    public Waypoint Waypoint { get; set; }


-    public Vector3 CurrentPointPosition => waypoint.GetWaypointPosition(_currentWaypointIndex);
+    public Vector3 CurrentPointPosition => Waypoint.GetWaypointPosition(_currentWaypointIndex);

    private int _currentWaypointIndex;
    
    private void Start()
    {
        _currentWaypointIndex = 0;
    }

    private void Update()
    {
        Move();
        if (CurrentPointPositionReached())
        {
            UpdateCurrentPointIndex();
        }
    }

    private void Move()
    {
-        Vector3 currentPosition = waypoint.GetWaypointPosition(_currentWaypointIndex);
+        Vector3 currentPosition = Waypoint.GetWaypointPosition(_currentWaypointIndex);
        transform.position = Vector3.MoveTowards(transform.position, currentPosition, moveSpeed * Time.deltaTime);
    }
    
    private bool CurrentPointPositionReached()
    {
        return Vector3.Distance(transform.position, CurrentPointPosition) < 0.1f;
    }

    private void UpdateCurrentPointIndex()
    {
-         int lastWaypointIndex = waypoint.Points.Length - 1;
+        int lastWaypointIndex = Waypoint.Points.Length - 1;
        if (_currentWaypointIndex < lastWaypointIndex)
        {
            _currentWaypointIndex++;
        }
        else
        {
            ReturnEnemyToPool();
            
        }
    }

    
    private void ReturnEnemyToPool()
    { 
        OnEndReached?.Invoke();
        ObjectPooler.ReturnToPool(gameObject);
    }
}

```

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


    public class Spawner : MonoBehaviour
    {
        [SerializeField]  private  int enemyCount = 10;
        // Btw = Between
        [SerializeField] private float delayBtwSpawns;
+        [SerializeField] private float delayBtwWaves = 1f;

+        private int _enemiesRemaining;
        
        private int _enemiesSpawned;
        private float _spawnTimer;
        private ObjectPooler _objectPooler;
+        private Waypoint _waypoint;

        private void Start()
        {
            _objectPooler = GetComponent<ObjectPooler>();
+            _waypoint = GetComponent<Waypoint>();
            
+            _enemiesRemaining = enemyCount;
        }

        private void Update()
        {
            _spawnTimer -= Time.deltaTime;
            if (_spawnTimer < 0)
            {
                _spawnTimer = delayBtwSpawns;
                if (_enemiesSpawned < enemyCount)
                {
                    SpawnEnemy();
                    _enemiesSpawned++;
                }
            }
        }
        
        // ReSharper disable Unity.PerformanceAnalysis
        private void SpawnEnemy()
        {
            GameObject newInstance = _objectPooler.GetInstanceFromPool();
+            Enemy enemy = newInstance.GetComponent<Enemy>();
+            enemy.Waypoint = _waypoint;
+            enemy.transform.localPosition = transform.position;
            newInstance.SetActive(true);
        }

        private IEnumerator NextWave()
        {
            yield return new WaitForSeconds(delayBtwWaves);
            _enemiesRemaining = enemyCount;
            _spawnTimer = 0f;
            _enemiesSpawned = 0;
        }
        
        private void RecordEnemyEndReached()
        {
            _enemiesRemaining--;
            if (_enemiesRemaining <= 0)
            {
                StartCoroutine(NextWave());
            }
        }
        private void OnEnable()
        {
            Enemy.OnEndReached += RecordEnemyEndReached;
        }
        
        private void OnDisable()
        {
            Enemy.OnEndReached -= RecordEnemyEndReached;
        }
    }


```
# 参考



Section4  15

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

github コミット分

https://github.com/RYA234/2DTowerDeffenceMyLearning/commit/11910d48f03711ddc605e52189f1390ff7bff5ef#diff-46c7b55c70ea70dd2cd12ac1fd22dc4c32464a6760f128f1d11711db34d38a60

章まとめ

https://qiita.com/RYA234/private/6d878a7958a3c760c8af