Parallels Desktop アースデイセール実施中 25%OFF

【Unity】タワーディフェンス(16) 防衛拠点とHP【クソゲー制作】

タワーディフェンスを作る(16)

Unity初心者が2Dタワーディフェンスゲームを制作中です。

今回は防衛拠点に敵が到達したら拠点のHPが減り、HPが0になったらゲームオーバーになるという処理を実装します。

環境
  • Mac mini (M1, 2020)
  • Unity 2022.3.36f1
目次

トップバーのUIを作る

まず、ゲーム画面の上部に表示されるUIを作ります。完成形はこんな感じになります。

タワーディフェンス176
STEP

ヒエラルキーのCanvasオブジェクト上で右クリックして「UI > Panel」を選択します。Canvasの配下にPanelオブジェクトが作成されるので、名前を「TopBar」にします。

STEP

TopBarがゲーム画面の上部に配置されるように「Rect Transform」を調整します。

タワーディフェンス177
STEP

「Image > Source Image」をNoneに、「Color」を透明にして、TopBarが見えなくなるようにします。

STEP

TopBarに「Horizontal Layout Group」コンポーネントを追加します。これは、子オブジェクトを横並びに整列させるためのコンポーネントです。

以下のように「Child Alignment(子オブジェクトの整列)」をMiddle Centerにして、左右の「Padding」と「Spacing(子オブジェクト同士の間隔)」を4にしました。

タワーディフェンス178
STEP

TopBarの配下に各オブジェクトを作成します。

  • TopBar
    • Stage: ステージ情報を入れておくためのオブジェクト。色は透明。
      • StageLabel: 「STAGE」というラベルを表示するためのTextMeshProオブジェクト。
      • StageText: ステージ番号を表示するためのTextMeshProオブジェクト。
    • FortressHp: 城のHP情報を入れておくためのオブジェクト。色は白の半透明。
      • FortressHpIcon: アイコンを表示するためのImageオブジェクト。
      • FortressHpLabel: 「HP」というラベルを表示するためのTextMeshProオブジェクト。
      • FortressHpSlider: 城の残りHPを表示するためのSliderオブジェクト。
      • FortressHpSliderScale: HPバーの目盛りをあらわすImageオブジェクトです。バーを20等分に区切る縦線の画像です。
    • Gold: お金の情報を入れておくためのオブジェクト。色は白の半透明。
      • GoldIcon: アイコンを表示するためのImageオブジェクト。
      • GoldLabel: 「GOLD」というラベルを表示するためのTextMeshProオブジェクト。
      • GoleText: 現在の所持金額を表示するためのTextMeshProオブジェクト。
    • Score: スコアの情報を入れておくためのオブジェクト。色は白の半透明。
      • ScoreIcon: アイコンを表示するためのImageオブジェクト。
      • ScoreLabel: 「SCORE」というラベルを表示するためのTextMeshProオブジェクト。
      • ScoreText: 現在のスコアを表示するためのTextMeshProオブジェクト。
    • Wave: ウェーブの情報を入れておくためのオブジェクト。色は白の半透明。
      • WaveIcon: アイコンを表示するためのImageオブジェクト。
      • WabeLabel: 「WAVE」というラベルを表示するためのTextMeshProオブジェクト。
      • WaveText: 現在のウェーブ番号を表示するためのTextMeshProオブジェクト。
      • TimeToNextWaveText: 次のウェーブまでの残り時間を表示するためのTextMeshProオブジェクト。
    • NextWaveButton: 次のウェーブを発生させるためのボタン。
      • NextWaveButtonText: ボタンのテキスト。
    • StartPauseButton: ゲームをスタート/ポーズするためのボタン。
      • StartPauseButtonText: ボタンのテキスト。

FortressHpSlider配下のHandle Slide Area(つまみの部分)は使わないので削除します。また、Fill Area「Rect Transform」「Left」「Right」の値をを0にします。敵のHpBarのときと同じですね。

STEP

オブジェクトの角を丸くするためにShapes2Dというアセットを使いました。無料です。

  1. アセットストアのShapes2Dのページに行き「Add to My Assets」ボタンをクリックします。
  2. UnityのPackage Managerでインポートします。
  3. 角を丸くしたいオブジェクトに「Shape(Shapes2D)」コンポーネントを追加します。
  4. インスペクターで「Shape (Script) > Roundness」の値を設定します。

防衛拠点(城)を作る

防衛拠点となる城のオブジェクトをマップ上に配置します。

STEP

城の画像(fortress.png)を「Assets > Images > Map」ディレクトリにインポートします。

このfortress.pngをヒエラルキーにドラッグ&ドロップすると簡単にオブジェクトを作成することができます。

タワーディフェンス179

名前は大文字で始まるFortressに修正しておきました。

STEP

ヒエラルキーの「Sprite Renderer > Additional Settings > Sorting Layer」を「Object」にします。これで城が最前面に表示されるようになりました。

STEP

「Transform > Position」を調整して、城が敵の移動経路のゴール地点に配置されるようにします。

タワーディフェンス180
STEP

敵が城に到達したときに当たり判定をしたいので、FortressオブジェクトにBox Collider 2Dコンポーネントを追加します。

物理的な挙動はせずに当たり判定だけしたいので、「Is Trigger」にチェックを入れます。

敵が防衛拠点(城)に到達したらHPを減らす

敵が防衛拠点(城)に到達したらHPを減らすスクリプトを書いていきます。

STEP

FortressControllerスクリプトを新規作成します。

using UnityEngine;
using UnityEngine.UI;

public class FortressController : MonoBehaviour
{
    [SerializeField, Header("最大HP")] private int maxHp = 20; // 防衛拠点の最大HP
    [SerializeField, Header("現在のHP")] private int currentHp; // 防衛拠点の現在のHP
    [SerializeField, Header("HP表示スライダー")] private Slider hpSlider; // HPを表示するスライダー

    private void Start()
    {
        // ゲーム開始時にHPを最大値に設定
        currentHp = maxHp;
        // HPスライダーを更新
        UpdateHpSlider();
    }

    /// <summary>
    /// 敵が防衛拠点に接触したときの処理
    /// </summary>
    private void OnTriggerEnter2D(Collider2D collision)
    {
        // 敵と接触した場合
        if (collision.TryGetComponent(out EnemyController enemy))
        {
            // ダメージを受ける
            TakeDamage();
            // 敵にゴール到達を通知する
            if (enemy != null)
            {
                enemy.ReachedGoal();
            }
        }
    }

    /// <summary>
    /// ダメージを受ける
    /// </summary>
    public void TakeDamage()
    {
        // HPを1減らす
        currentHp--;
        // HPスライダーを更新
        UpdateHpSlider();

        // HPが0以下になったらゲームオーバー
        if (currentHp <= 0)
        {
            GameOver();
        }
    }

    /// <summary>
    /// HPスライダーを更新する
    /// </summary>
    private void UpdateHpSlider()
    {
        // スライダーの最大値を設定
        hpSlider.maxValue = maxHp;
        // スライダーの値を現在のHPに設定
        hpSlider.value = currentHp;
    }

    /// <summary>
    /// ゲームオーバー処理
    /// </summary>
    private void GameOver()
    {
        // ゲームオーバー処理を記述
        Debug.Log("ゲームオーバー");
    }
}
STEP

FortressControllerスクリプトをFortressオブジェクトにドラッグ&ドロップしてアタッチします。

STEP

Fortressオブジェクトのインスペクターで、「Fortress Controller (Script) > Hp Slider」にFortressHpSliderオブジェクトをドラッグ&ドロップしてアサインします。

タワーディフェンス181
STEP

EnemyControllerスクリプトにメソッドを追加します。

    // ...省略...

    // ここから
    /// <summary>
    /// 敵がゴールに到達した
    /// </summary>
    public void ReachedGoal()
    {
        DestroyEnemy(); // 敵を破壊する
    }
    // ここまで

    // ...省略...

これでゲームを実行すればうまくいくと思ったのですがダメでした。Geminiに頼っても解決せず、100万年悩んだ末にChatGPTに相談したところあっさりと解決。ChatGPTのほうが賢いかも。解決策は次のSTEPで。

STEP

「Assets > Prefabs > Enemy」をダブルクリックしてプレハブの編集モードに入ります。そして、EnemyオブジェクトにRigidbody 2Dコンポーネントを追加します。

「Gravity Scale」を「0」にして重力を無効化します。

タワーディフェンス182

というわけで、当たり判定をするには城と敵のどちらかにRigidbodyをつける必要があるのでした。

動作確認

ゲームを実行して動作確認をします。

敵が城に接触すると、敵が消えて城のHPは減るようになりました。いえい。

さいごに

今回、新しいことは何もしていないんですけど、Rigidbodyのところで引っ掛かったのが悔しいです!

でわでわ

タワーディフェンスを作る(16)

この記事が気に入ったら
いいね または フォローしてね!

シェアしてね

コメント

コメントする

目次