タワーデフェンスゲーム　Unity タレットアプデ機能  1/2　35 Dボタンを押すと、タレットのアプデで実行される

# 概要
目次

https://qiita.com/RYA234/private/8985b1fe637bcd6fccac

今回はタレットのアップグレード機能を追加します。
以下gifアニメは Dボタンを押すとタレットの威力が２から４に増加している様子です。

![adsafdsfdsa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/0dfb8b3c-a994-0b8f-e3e4-a8a18c70a6cf.gif)



# 開発環境

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

# UnityEditor上の設定
プレハブ化したタレットオブジェクトにTurretUpgradeクラスをアタッチします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/871d6069-977c-ced7-7a18-5edb5c308a65.png)


# 実装のポイント
新規クラスとしてTurretUpgradeクラスを追加します。
TurreUpgradeクラスはDボタンを押すとタレットの弾の威力を上げる処理を追加します。

既存クラスProjectile TurretProjectileクラスについて変数DamageをTurretProjectileに移動するようリファクタリングします。TurretProjectクラスの [SerializeField] protected float damage で数量を決定し、TurretProject.Damageで他のクラス(TurretUpgrade Projectileクラス)にアクセスできるようにしています。
（下図参照）


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710623/a2474626-cabe-9641-e896-2fdc0e5a0d13.png)


# コード部分
## Projectile
```diff_c_sharp:Projectile.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Projectile : MonoBehaviour
{
    public static Action<Enemy, float> OnEnemyHit;
    [SerializeField] protected float moveSpeed = 10f;
    protected Enemy _enemyTarget;
-     [SerializeField] protected float damage = 2f;
    [SerializeField] private float minDistanceToDealDamage = 0.1f;
    
+    public float Damage { get; set; }
    
    public TurretProjectTile TurretOwner { get; set; }
    private float _nextAttackTime;
    
    void Start()
    {
        
    }

    // Update is called once per frame
    protected virtual void Update()
    {
        if (_enemyTarget != null)
        {
            MoveProjecttile();
            RotateProjetile();
        }
        
    }

    protected virtual void MoveProjecttile()
    {
        transform.position = Vector2.MoveTowards(transform.position,_enemyTarget.transform.position,moveSpeed * Time.deltaTime);
        float distanceToTarget = (_enemyTarget.transform.position - transform.position).magnitude;
        if (distanceToTarget < minDistanceToDealDamage)
        {

-             OnEnemyHit?.Invoke(_enemyTarget, damage);
-             _enemyTarget.EnemyHealth.DealDamage(damage);
+            OnEnemyHit?.Invoke(_enemyTarget, Damage);
+            _enemyTarget.EnemyHealth.DealDamage(Damage);
            TurretOwner.ResetTurretProjectile();
            ObjectPooler.ReturnToPool(gameObject);
            
        }
    }

    private void RotateProjetile()
    {
        Vector3 enemyPos = _enemyTarget.transform.position - transform.position;
        float angle = Vector3.SignedAngle(transform.up, enemyPos, transform.forward);
        transform.Rotate(0f,0f,angle);
    }

    
    public void SetEnemy(Enemy enemy)
    {
        _enemyTarget = enemy;
        
    }
    public void ResetProjectile()
    {
        _enemyTarget = null;
        transform.localRotation = Quaternion.identity;
    }    
    
}



```



## TurretProjectile
```diff_c_sharp:TurretProjectile.cs
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TurretProjectTile : MonoBehaviour
{

    [SerializeField] protected Transform projecttileSpawnPosition;
    protected ObjectPooler _pooler;
    protected Turrets _turret;
    protected Projectile _currentProjectileLoaded;
    [SerializeField] protected float delayBtwAttacks = 0.3f;
+    [SerializeField] protected float damage = 2f;
+    public float Damage { get; set; }
+    public float DelayPerShot { get; set; }
    
    protected float _nextAttackTime;
    
    private void Start()
    {
        _pooler = GetComponent<ObjectPooler>();
        _turret = GetComponent<Turrets>();

+        Damage = damage;
+        DelayPerShot = delayBtwAttacks;
        LoadProjecttile();
        
    }

    protected virtual void Update()
    {
        // if (Input.GetKeyDown(KeyCode.G))
        // {
        //     LoadProjecttile();
        // }
        if (IsTurrentEmpty())
        {
            LoadProjecttile();
        }
        
        if(Time.time > _nextAttackTime)
        {
            if (_turret.CurrentEnemyTarget != null && _currentProjectileLoaded != null &&
                _turret.CurrentEnemyTarget.EnemyHealth.CurrentHealth > 0f)
            {
                _currentProjectileLoaded.transform.parent = null;
                _currentProjectileLoaded.SetEnemy((_turret.CurrentEnemyTarget));
            }

-             _nextAttackTime = Time.time + delayBtwAttacks;
+            _nextAttackTime = Time.time + DelayPerShot;
        }

        
    }

    protected virtual void LoadProjecttile()
    {
        GameObject newInstance = _pooler.GetInstanceFromPool();
        newInstance.transform.position = projecttileSpawnPosition.position;
        newInstance.transform.SetParent(projecttileSpawnPosition);

        _currentProjectileLoaded = newInstance.GetComponent<Projectile>();
        _currentProjectileLoaded.TurretOwner = this;
        _currentProjectileLoaded.ResetProjectile();
+        _currentProjectileLoaded.Damage = Damage;
        
        newInstance.SetActive(true);
        

    }

    private bool IsTurrentEmpty()
    {
        return _currentProjectileLoaded == null;
    }
    public void ResetTurretProjectile()
    {
        _currentProjectileLoaded = null;
    }


}



```


## TurretUpgrade
```diff_c_sharp:TurretUpgrade.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TurretUpgrade : MonoBehaviour
{
    
    [SerializeField] private int upgradeInitialCost;
    [SerializeField] private int upgradeCostIncremental;
    [SerializeField] private float damageIncremental;
    [SerializeField] private float delayReduce;
    private TurretProjectTile _turretProjectTile;
    private void Start()
    {
        _turretProjectTile = GetComponent<TurretProjectTile>();
    }

    // Update is called once per frame
   private void Update()
   {
       if(Input.GetKeyDown(KeyCode.D))
       {
           UpgradeTurret();
       }
   }

   private void UpgradeTurret()
   {
       _turretProjectTile.Damage += damageIncremental;
       _turretProjectTile.DelayPerShot -= delayReduce;
   }
}



```

# 参考


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

github コミット分

https://github.com/RYA234/2DTowerDeffenceMyLearning/commit/236e9574d39f101363b23bf13c85f9f3bc918f11