サイトアイコン StudioFun

Unity チュートリアルのタワーディフェンステンプレートを触ってみる(7)

Unity チュートリアルのタワーディフェンステンプレートを触ってみる(6) では Tower.cs の継承元となっている Targetable.cs スクリプトの解説を行った。今回は Tower.cs の解説を行っていく。

「Tower.cs」 は 「Targetable.cs」 を継承し、「Targetable.cs」 は 「DamageableBehaviour.cs」 を継承している。

前回は「Targetable.cs」の行った。「Tower.cs」 を行っていく。Targetable.cs の解説についてはこちらを参照してほしい。

Unity チュートリアルのタワーディフェンステンプレートを触ってみる(5) では Tower.cs の継承元となっている DamageableBehaviour.cs スクリプトの解説を行った。今回は更に Tower.cs の継承元となっている Targetable.cs の解説を行っていく。
Unity チュートリアルのタワーディフェンステンプレートを触ってみる(6) | Stud... - StudioFun

1.タワー編 – Tower.cs

Tower.cs について稚拙ながら解説

「Tower.cs」は「Asset/Scripts/TowerDefense/Towers/Tower.cs」の指しておりスクリプトについては以下の通り。内容としてはタワーのアップグレード・ダウングレード・売却の処理を主に行っている。

[cce_csharp]using System;
using ActionGameFramework.Health;
using Core.Utilities;
using TowerDefense.Level;
using TowerDefense.Towers.Placement;
using TowerDefense.UI.HUD;
using UnityEngine;

namespace TowerDefense.Towers
{
    /// <summary>
    /// Common functionality for all types of towers
    /// </summary>
    public class Tower : Targetable
    {
        /// <summary>
        /// The tower levels associated with this tower
        /// </summary>
        public TowerLevel[] levels;

        /// <summary>
        /// A generalised name common to a levels
        /// </summary>
        public string towerName;

        /// <summary>
        /// The size of the tower's footprint
        /// </summary>
        public IntVector2 dimensions;

        /// <summary>
        /// The physics mask the tower searches on
        /// </summary>
        public LayerMask enemyLayerMask;

        /// <summary>
        /// The current level of the tower
        /// </summary>
        public int currentLevel { get; protected set; }

        /// <summary>
        /// Reference to the data of the current level
        /// </summary>
        public TowerLevel currentTowerLevel { get; protected set; }

        /// <summary>
        /// Gets whether the tower can level up anymore
        /// </summary>
        public bool isAtMaxLevel
        {
            get { return currentLevel == levels.Length - 1; }
        }

        /// <summary>
        /// Gets the first level tower ghost prefab
        /// </summary>
        public TowerPlacementGhost towerGhostPrefab
        {
            get { return levels[currentLevel].towerGhostPrefab; }
        }

        /// <summary>
        /// Gets the grid position for this tower on the <see cref="placementArea"/>
        /// </summary>
        public IntVector2 gridPosition { get; private set; }

        /// <summary>
        /// The placement area we've been built on
        /// </summary>
        public IPlacementArea placementArea { get; private set; }

        /// <summary>
        /// The purchase cost of the tower
        /// </summary>
        public int purchaseCost
        {
            get { return levels[0].cost; }
        }

        /// <summary>
        /// The event that fires off when a player deletes a tower
        /// </summary>
        public Action towerDeleted;

        /// <summary>
        /// The event that fires off when a tower has been destroyed
        /// </summary>
        public Action towerDestroyed;

        /// <summary>
        /// Provide the tower with data to initialize with
        /// </summary>
        /// <param name="targetArea">The placement area configuration</param>
        /// <param name="destination">The destination position</param>
        public virtual void Initialize(IPlacementArea targetArea, IntVector2 destination)
        {
            placementArea = targetArea;
            gridPosition = destination;

            if (targetArea != null)
            {
                transform.position = placementArea.GridToWorld(destination, dimensions);
                transform.rotation = placementArea.transform.rotation;
                targetArea.Occupy(destination, dimensions);
            }

            SetLevel(0);
            if (LevelManager.instanceExists)
            {
                LevelManager.instance.levelStateChanged += OnLevelStateChanged;
            }
        }

        /// <summary>
        /// Provides information on the cost to upgrade
        /// </summary>
        /// <returns>Returns -1 if the towers is already at max level, other returns the cost to upgrade</returns>
        public int GetCostForNextLevel()
        {
            if (isAtMaxLevel)
            {
                return -1;
            }
            return levels[currentLevel + 1].cost;
        }

        /// <summary>
        /// Kills this tower
        /// </summary>
        public void KillTower()
        {
            // Invoke base kill method
            Kill();
        }

        /// <summary>
        /// Provides the value recived for selling this tower
        /// </summary>
        /// <returns>A sell value of the tower</returns>
        public int GetSellLevel()
        {
            return GetSellLevel(currentLevel);
        }

        /// <summary>
        /// Provides the value recived for selling this tower of a particular level
        /// </summary>
        /// <param name="level">Level of tower</param>
        /// <returns>A sell value of the tower</returns>
        public int GetSellLevel(int level)
        {
            // sell for full price if waves haven't started yet
            if (LevelManager.instance.levelState == LevelState.Building)
            {
                int cost = 0;
                for (int i = 0; i <= level; i++)
                {
                    cost += levels[i].cost;
                }

                return cost;
            }
            return levels[currentLevel].sell;
        }

        /// <summary>
        /// Used to (try to) upgrade the tower data
        /// </summary>
        public virtual bool UpgradeTower()
        {
            if (isAtMaxLevel)
            {
                return false;
            }
            SetLevel(currentLevel + 1);
            return true;
        }

        /// <summary>
        /// A method for downgrading tower
        /// </summary>
        /// <returns>
        /// <value>false</value> if tower is at lowest level
        /// </returns>
        public virtual bool DowngradeTower()
        {
            if (currentLevel == 0)
            {
                return false;
            }
            SetLevel(currentLevel - 1);
            return true;
        }

        /// <summary>
        /// Used to set the tower to any valid level
        /// </summary>
        /// <param name="level">
        /// The level to upgrade the tower to
        /// </param>
        /// <returns>
        /// True if successful
        /// </returns>
        public virtual bool UpgradeTowerToLevel(int level)
        {
            if (level < 0 || isAtMaxLevel || level >= levels.Length)
            {
                return false;
            }
            SetLevel(level);
            return true;
        }

        public void Sell()
        {
            Remove();
        }

        /// <summary>
        /// Removes tower from placement area and destroys it
        /// </summary>
        public override void Remove()
        {
            base.Remove();
            
            placementArea.Clear(gridPosition, dimensions);
            Destroy(gameObject);
        }

        /// <summary>
        /// unsubsribe when necessary
        /// </summary>
        protected virtual void OnDestroy()
        {
            if (LevelManager.instanceExists)
            {
                LevelManager.instance.levelStateChanged += OnLevelStateChanged;
            }
        }

        /// <summary>
        /// Cache and update oftenly used data
        /// </summary>
        protected void SetLevel(int level)
        {
            if (level < 0 || level >= levels.Length)
            {
                return;
            }
            currentLevel = level;
            if (currentTowerLevel != null)
            {
                Destroy(currentTowerLevel.gameObject);
            }

            // instantiate the visual representation
            currentTowerLevel = Instantiate(levels[currentLevel], transform);

            // initialize TowerLevel
            currentTowerLevel.Initialize(this, enemyLayerMask, configuration.alignmentProvider);

            // health data
            ScaleHealth();

            // disable affectors
            LevelState levelState = LevelManager.instance.levelState;
            bool initialise = levelState == LevelState.AllEnemiesSpawned || levelState == LevelState.SpawningEnemies;
            currentTowerLevel.SetAffectorState(initialise);
        }

        /// <summary>
        /// Scales the health based on the previous health
        /// Requires override when the rules for scaling health on upgrade changes
        /// </summary>
        protected virtual void ScaleHealth()
        {
            configuration.SetMaxHealth(currentTowerLevel.maxHealth);
            
            if (currentLevel == 0)
            {
                configuration.SetHealth(currentTowerLevel.maxHealth);
            }
            else
            {
                int currentHealth = Mathf.FloorToInt(configuration.normalisedHealth * currentTowerLevel.maxHealth);
                configuration.SetHealth(currentHealth);
            }
        }

        /// <summary>
        /// Intiailises affectors based on the level state
        /// </summary>
        protected virtual void OnLevelStateChanged(LevelState previous, LevelState current)
        {
            bool initialise = current == LevelState.AllEnemiesSpawned || current == LevelState.SpawningEnemies;
            currentTowerLevel.SetAffectorState(initialise);
        }
    }
}[/cce_csharp]

14行目 : 「public class Tower : Targetable」これは前回解説した「Targetable」を継承していることを指している。「Targetable」についてはこちらを参照してほしい。

95行目 : 「public virtual void Initialize(IPlacementArea targetArea, IntVector2 destination)」では「Tower」の初期化を行っている。引数としては配置可能エリアと配置先を引数としている。

118行目 : 「public int GetCostForNextLevel()」では次のレベルアップにかかるコストの取得を行っている。

130行目 : 「public void KillTower()」では継承元である「DamageableBehaviour」の Kill 関数を用いて自身のタワーオブジェクトの削除を行っている。

140行目 : 「public int GetSellLevel()」ではタワーの販売価格を取得している。また、この関数は以下の「public int GetSellLevel(int level)」に現在のレベルを与えることで販売価格の計算を行っている。

150行目 : 「public int GetSellLevel(int level)」ではレベルに応じたタワーの販売価格を取得している。

169行目 : 「public virtual bool UpgradeTower()」ではタワーのアップグレードを行っている。この時すでに最大レベルとなっている場合はアップグレードは行われない。

185行目 : 「public virtual bool DowngradeTower()」ではタワーのダウングレードを行っている。この時、最小レベルの場合はダウングレードは行われない。

204行目 : 「public virtual bool UpgradeTowerToLevel(int level)」では任意のレベルまでアップグレードを行っている。この時すでにタワーが任意のレべルまで達していた場合はアップグレードをは行われない。

214行目 : 「public void Sell()」ではタワーの削除を行っている。内容については以下の「public override void Remove()」と同様

222行目 : 「public override void Remove()」では削除処理を行っている。「DamageableBehaviour」の Remove 関数を実行後、配置しているエリアのクリアとゲームオブジェクトの削除を行っている。

233行目 : 「protected virtual void OnDestroy()」ではタワーのゲームオブジェクトが Destroy された時の処理を行っている。LevelManager クラスに状態を設定しているのだが、こちらについては「LevelManager 」の設定が出てきた時にまとめて解説したいと思う。

244行目 : 「protected void SetLevel(int level)」では既存のデータから引き続きプレイするときに用いる。保存しているレベルを与えることで続きから行えるようになる。

275行目 : 「protected virtual void ScaleHealth()」でが体力ゲージの設定を行っている。

293行目 : 「protected virtual void OnLevelStateChanged(LevelState previous, LevelState current)」ではレベルが変更となった時の処理を定義している。引数として前のレベルと現在のレベルを与え、「TowerLevel」の設定を行っている。「TowerLevel」についてはこちらを参照してほしい。

Unity チュートリアルのタワーディフェンステンプレートを触ってみる(2) では実際に Unity を用いてタワーディフェンステンプレートを用いてタワーの設定データの作成と解説を行った。今回は実際にTowerLevel プレハブとそれに付随するスクリプトの解説を行っていく。
Unity チュートリアルのタワーディフェンステンプレートを触ってみる(3) | Stud... - StudioFun
モバイルバージョンを終了