Unity チュートリアルのタワーディフェンステンプレートを触ってみる(7)
Unity チュートリアルのタワーディフェンステンプレートを触ってみる(6) では Tower.cs の継承元となっている Targetable.cs スクリプトの解説を行った。今回は Tower.cs の解説を行っていく。
「Tower.cs」 は 「Targetable.cs」 を継承し、「Targetable.cs」 は 「DamageableBehaviour.cs」 を継承している。
前回は「Targetable.cs」の行った。「Tower.cs」 を行っていく。Targetable.cs の解説についてはこちらを参照してほしい。
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」についてはこちらを参照してほしい。