0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

タワーデフェンスゲーム Unity タレットアプデ機能 2/2 通貨システムの実装

Last updated at Posted at 2023-05-01

概要

目次

今回は通貨システムを実装します。
通貨パラメーターを追加して、タレットを強化する時に10減少し敵を倒した時に1増加するようにします。
以下gifアニメは
Dボタンを押してタレットを強化する際に通貨が10減少し敵を倒した時に1増加しています。
尚通貨はprivate変数なのでインスペクターのデバッグモードで確認します。

currency.gif

開発環境

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

UnityEditor上の設定

新規オブジェクトCurrencySystemを作成して CurrencySystemスクリプトをアタッチします。

image.png

実装のポイント

1.通貨システムを実装
新規クラスにCurrencySysytemクラスを作成し、TurretUpgradeクラスにメソッドを追加します。

下図は敵が死亡した時に通貨が得られるときの処理(Observeパターン)
image.png

下図はタレットをアプデした時に通過が減る時の処理

image.png

通貨の値はPlayerPrefsというクラスを使って操作します。PlayerPrefsはゲームデータのセーブ・ロードを行うクラスのようです。

2.どのEnemyがKillされたか識別するためにActionの引数にEnemyクラスを加える。
既存クラスSpawner LevelManager EnemyHealth Enemyで一部改修を行います。

コード部分

Enemy

Enemy.cs
using System;
using UnityEngine;

public class Enemy : MonoBehaviour
{
-    public static Action OnEndReached;
+    public static Action<Enemy> OnEndReached;

    [SerializeField] private float moveSpeed = 3f;
    public Waypoint Waypoint { get; set; }
    public Vector3 CurrentPointPosition => Waypoint.GetWaypointPosition(_currentWaypointIndex);
    private int _currentWaypointIndex;
    private EnemyHealth _enemyHealth;
    public EnemyHealth EnemyHealth { get; set; }
    
    
    private void Start()
    {
        _currentWaypointIndex = 0;
        _enemyHealth = GetComponent<EnemyHealth>();
        EnemyHealth = GetComponent<EnemyHealth>();

    }

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

    private void Move()
    {
        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;
        if (_currentWaypointIndex < lastWaypointIndex)
        {
            _currentWaypointIndex++;
        }
        else
        {
            EndPointReached();
            
        }
    }

    
    private void EndPointReached()
    { 
-         OnEndReached?.Invoke();
+        OnEndReached?.Invoke(this);
        _enemyHealth.ResetHealth();
        ObjectPooler.ReturnToPool(gameObject);
    }

    public void ResetEnemy()
    {
        _currentWaypointIndex = 0;
    }
}


EnemyHealth

EnemyHealth.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using UnityEngine;
using UnityEngine.UI;

public class EnemyHealth : MonoBehaviour
{
-    public static Action OnEnemyKilled;
+    public static Action<Enemy> OnEnemyKilled;

    // Start is called before the first frame update
    [SerializeField] private GameObject healthBarPrefab;
    [SerializeField] private Transform barPosition;

    [SerializeField] private float initialHealth = 10f;
    [SerializeField] private float maxHealth = 10f;

    public float CurrentHealth { get; set; }
    private Image _healthBar;
+    private Enemy _enemy;
    void Start()
    {
        CreateHealthBar();
        CurrentHealth = initialHealth;

+        _enemy = GetComponent<Enemy>();
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            DealDamage(5f);
        }

        _healthBar.fillAmount = Mathf.Lerp(_healthBar.fillAmount, CurrentHealth / maxHealth, Time.deltaTime * 10f);
    }

    private void CreateHealthBar()
    {
        GameObject newBar = Instantiate(healthBarPrefab,barPosition.position,Quaternion.identity);
        newBar.transform.SetParent(transform);
        
        EnemyHealthContainer container = newBar.GetComponent<EnemyHealthContainer>();
        _healthBar = container.FillAmountImage;
    }

    public void DealDamage(float damageReceived)
    {
        CurrentHealth -= damageReceived;
        if (CurrentHealth <= 0)
        {
            CurrentHealth = 0;
            Die();
        }
    }

    public void ResetHealth()
    {
        CurrentHealth = initialHealth;
        _healthBar.fillAmount = 1f;
    }
    private void Die()
    {
-        OnEnemyKilled?.Invoke();
+        OnEnemyKilled?.Invoke(_enemy);
        CurrentHealth = initialHealth;
        _healthBar.fillAmount = 1f;
        ObjectPooler.ReturnToPool(gameObject);
    }
    
    
}



CurrencySystem

CurrencySystem.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CurrencySystem : Singleton<CurrencySystem>
{
    [SerializeField] private int coinTest;
    private string CURRENCY_SAVE_KEY = "MYGAME_CURRENCY";
    
    
    public int TotalCoins { get; set; }
    
    void Start()
    {
        PlayerPrefs.DeleteKey(CURRENCY_SAVE_KEY);
        LoadCoins();
    }

    private void LoadCoins()
    {
        TotalCoins = PlayerPrefs.GetInt(CURRENCY_SAVE_KEY, coinTest);
    }

    public void AddCoins(int amount)
    {
        TotalCoins += amount;
        PlayerPrefs.SetInt(CURRENCY_SAVE_KEY,TotalCoins);
        PlayerPrefs.Save();
    }

    public void RemoveCoins(int amount)
    {
        if (TotalCoins >= amount)
        {
            TotalCoins -= amount;
            PlayerPrefs.SetInt(CURRENCY_SAVE_KEY,TotalCoins);
            PlayerPrefs.Save();
        }
    }


    private void AddCoins(Enemy enemy)
    {
        AddCoins(1);
    }

    private void OnEnable()
    {
        EnemyHealth.OnEnemyKilled += AddCoins;
    }

    private void OnDisable()
    {
        EnemyHealth.OnEnemyKilled -= AddCoins;
    }
}



LevelManager

LevelManager.cs
using System;
using UnityEngine;


public class LevelManager : MonoBehaviour
{
    [SerializeField] private int lives = 10;

    public int TotalLives { get; set; }
    private void Start()
    {
        TotalLives = lives;
    }
-    private void ReduceLives()
+    private void ReduceLives(Enemy enemy)
    {
        TotalLives--;
        if (TotalLives <= 0)
        {
            TotalLives = 0;
        }
    }
    private void OnEnable()
    {
        Enemy.OnEndReached += ReduceLives;  
    }

    private void OnDisable()
    {
        Enemy.OnEndReached -= ReduceLives;  
    }
}



Spawner

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;
            enemy.ResetEnemy();
            newInstance.SetActive(true);
        }

        private IEnumerator NextWave()
        {
            yield return new WaitForSeconds(delayBtwWaves);
            _enemiesRemaining = enemyCount;
            _spawnTimer = 0f;
            _enemiesSpawned = 0;

        }
        
        private void RecordEnemy(Enemy enemy)
        {
            _enemiesRemaining--;
            if (_enemiesRemaining <= 0)
            {
                StartCoroutine(NextWave());
            }
        }

        private void OnEnable()
        {
            Enemy.OnEndReached += RecordEnemy;
            EnemyHealth.OnEnemyKilled += RecordEnemy;
        }


        private void OnDisable()
        {
            Enemy.OnEndReached -= RecordEnemy;
            EnemyHealth.OnEnemyKilled -= RecordEnemy;
        }
    }



TurretUpgrade

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;
    
+    public int UpgradeCost { get; set;}
    private void Start()
    {
        _turretProjectTile = GetComponent<TurretProjectTile>();
+        UpgradeCost = upgradeInitialCost;
    }

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

   private void UpgradeTurret()
   {
+       if (CurrencySystem.Instance.TotalCoins >= UpgradeCost)
+       {
           _turretProjectTile.Damage += damageIncremental;
           _turretProjectTile.DelayPerShot -= delayReduce;
+           UpdateUpgrade();
+       }
   }

+   private void UpdateUpgrade()
+   {
+       CurrencySystem.Instance.RemoveCoins(UpgradeCost);
+       UpgradeCost += upgradeCostIncremental;
+   }
}



参考

PlayerPrefs

image.png

Section6 36

github コミット分

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?