TD-ゲームクリアの処理を作る part13

ゲームオーバー作ったら、そらゲームクリアでしょう。今回はWaveをこなした時点でクリアとします。

目次

ゲームクリアの表示を作る

ここの表示は基本的にはクリアと同じものを作ります。違いとしてはボタンが不要です。押したら再スタートの機能があってもいいですけどね。

  • PanelGameClearを作成する
    • PanelGameOverを右クリック>Duplicate(複製)
    • 名前を変更:PanelGameClear
  • TextMeshProの変更
    • テキストを変更:Game Clear!!
    • テキストの色を変更:青
  • ボタンを削除

テキストの色を変更する必要は無いんですが、ゲームオーバーと同じだと雰囲気が出ない気がするので・・・

クリアの処理を実装

敵が何らかでやられたことを知らせる処理を追加

クリア判定を行うために必要となる処理を先に追加します。その中の1つに、すべての敵を対処することが含まれます。敵は、

  • ディフェンダーに倒される
  • お城まで到達する

のいずれかで消費されます。このどちらかが行われたのを知るためにEnemyControllerを修正します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using Cinemachine;

public class EnemyController : MonoBehaviour
{
    private EnemyData enemyData; // 敵のデータ
    private Castle targetCastle; // お城

    private float hp;
    private float power;
    private float speed;

    public static UnityEvent<EnemyController> OnAnyDestroyed = new UnityEvent<EnemyController>();

    public void Initialize(EnemyData enemyData, LineRenderer lineRenderer, Castle targetCastle)
    {
        this.enemyData = enemyData;

        hp = enemyData.maxHp;
        power = enemyData.power;
        speed = enemyData.speed;
        GetComponent<LineMover>().SetSpeed(speed);

        var spriteRenderer = GetComponent<SpriteRenderer>();
        spriteRenderer.sprite = enemyData.enemySprite;

        var lineMover = GetComponent<LineMover>();
        lineMover.Initialize(0, speed, lineRenderer);

        this.targetCastle = targetCastle;

        lineMover.OnEndReached += (sender, e) =>
        {
            Debug.Log("お城に到着したよ!");
            if (this.targetCastle != null)
            {
                this.targetCastle.TakeDamage(power);

                var impulseSource = GetComponent<CinemachineImpulseSource>();
                impulseSource.GenerateImpulse(0.1f);
            }
            OnAnyDestroyed.Invoke(this);
            Destroy(gameObject);
        };
    }

    public void TakeDamage(float damage)
    {
        hp -= damage;
        Debug.Log("HP: " + hp + "/" + enemyData.maxHp);
        if (hp <= 0)
        {
            OnAnyDestroyed.Invoke(this);
            Destroy(gameObject);
        }
    }
}

内容的にはお城がやられたときとなんだか似てますが、必ずお城にダメージを与えているTakeDamageより後にOnAnyDestroyedを行うようにしてください。イベントが発生するタイミングはほんの一瞬ですが、順序が変わってしまうと、最後の1擊でお城が破壊されたにも関わらず、ゲームクリアの判定が勝ってしまう場合があります。ご注意ください。

クリアの判定について

今回制作しているタワーディフェンスで、クリアの判定はどの様に取ることができるでしょうか。

  • すべての敵をしのぎ切った
    • 倒すでも良い
    • お城に突っ込んで消費したでも良い
  • お城が無事

上記を満たすためには、Waveで登場する敵の数と、敵がなんらかの方法でやられたという情報を知る必要があります。クリアの表示処理も合わせると、次のようなプログラムになります。

public class GameManager : MonoBehaviour
{
    [SerializeField] private GameObject panelGameOver;
    [SerializeField] private GameObject panelGameClear;

    [SerializeField] private WaveData waveData;
    private int totalEnemyCount = 0;
    private int currentEnemyCount = 0;

    private void Start()
    {
        panelGameOver.SetActive(false);
        panelGameClear.SetActive(false);

        // waveデータに含まれる敵の数を調べる
        foreach (var enemyData in waveData.enemyDataList)
        {
            if (enemyData != null)
            {
                totalEnemyCount += 1;
            }
        }

        // 敵がいなくなったら
        EnemyController.OnAnyDestroyed.AddListener((enemy) =>
        {
            // カウントアップして
            currentEnemyCount += 1;

            // すべての敵を倒しつつ、ゲームオーバーになってなければ
            if (totalEnemyCount <= currentEnemyCount && panelGameOver.activeSelf == false)
            {
                // クリア
                panelGameClear.SetActive(true);
            }
        });
    }
}
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメント一覧 (1件)

コメントする

目次