クリア&ゲームオーバー処理の作り方(1):GameManager等の変更

前回までで敵やコインを作ったので、これでゲームをクリアしたりゲームオーバーになったりする要素がそろいました。

そこで、ここからはステージクリア処理とゲームオーバー処理を作っていきます。主な作業内容は次の2つです。

  1. GameManager等のスクリプトの変更
  2. クリア・ゲームオーバー画面用のキャンバスの作成

まず、ここではGameManager等のいくつかのスクリプトを変更していきましょう。色々変更箇所があってややこしいので、注意しながら作業を進めてください。

スポンサーリンク

GameManagerの変更

はじめにGameManagerスクリプトを変更します。GameManager.csを次のように書き換えてください(※変更箇所が多いので全文を載せます)。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;	//追加

[RequireComponent(typeof(MoveSceneManager))]
[RequireComponent(typeof(SaveManager))]
[RequireComponent(typeof(SoundManager))]
[DefaultExecutionOrder(-5)]
public class GameManager : SingletonMonoBehaviour<GameManager>
{

  [Header("シーンロード時に自動生成するプレハブを登録")]
  [SerializeField]
  GameObject[] prefabs = null;

  //追加
  [Header("UIの設定")]
  [SerializeField]
  GameObject clearCanvasPrefab = null;
  [SerializeField]
  GameObject gameOverCanvasPrefab = null;
  [SerializeField]
  string nextButtonName = "NextButton";
  [SerializeField]
  string retryButtonName = "RetryButton";
  [SerializeField]
  string titleButtonName = "TitleButton";

  MoveSceneManager moveSceneManager;
  SaveManager saveManager;
  SoundManager soundManager;

  //追加
  bool isClear = false;
  bool isGameOver = false;
  int numOfCoins = 0;
  int correctedCoins = 0;

  public int CorrectedCoins
  {
    set
    {
      correctedCoins = value;

      if(correctedCoins >= numOfCoins)
      {
        Clear();
      }
    }
    get
    {
      return correctedCoins;
    }
  }

  protected override void Awake()
  {
    base.Awake();

    if (Debug.isDebugBuild)
    {
      
    }

    moveSceneManager = GetComponent<MoveSceneManager>();
    saveManager = GetComponent<SaveManager>();
    soundManager = GetComponent<SoundManager>();
  }

  void Start()
  {
    if (Debug.isDebugBuild)
    {
      InstantiateWhenLoadScene();
      InitGame();	//追加
    }
  }

  void Update()
  {
        
  }

  public void InstantiateWhenLoadScene()
  {
    if(moveSceneManager.SceneName == "Title")
    {
      return;
    }

    foreach (GameObject prefab in prefabs)
    {
      Instantiate(prefab, transform.position, Quaternion.identity);
    }
  }

  //--ここから追加--

  //ゲーム初期化メソッド
  public void InitGame()
  {
    isClear = false;
    isGameOver = false;
    numOfCoins = GameObject.FindGameObjectsWithTag("Coin").Length;
    correctedCoins = 0;
  }

  public void Clear()
  {
    if (isClear || isGameOver)
    {
      return;
    }

    isClear = true;
    GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>().isActive = false;

    //クリア画面のキャンバスを生成
    Instantiate(clearCanvasPrefab, transform.position, Quaternion.identity);

    //ボタンのコンポーネントを取得
    Button nextButton = GameObject.Find(nextButtonName).GetComponent<Button>();
    Button titleButton = GameObject.Find(titleButtonName).GetComponent<Button>();

    //ボタンに、クリックしたときの処理を登録
    //ただし「次のステージ」ボタンは次のステージがないときは押せないようにする
    if(moveSceneManager.CurrentSceneNum < moveSceneManager.NumOfScene - 1)
    {
      nextButton.onClick.AddListener(() => moveSceneManager.MoveToScene(moveSceneManager.CurrentSceneNum + 1));
    }
    else
    {
      nextButton.interactable = false;
    }

    titleButton.onClick.AddListener(() => moveSceneManager.MoveToScene(0)); //タイトル画面に戻るので、シーン番号は0番
  }

  public void GameOver()
  {
    if (isGameOver || isClear)
    {
      return;
    }

    isGameOver = true;
    GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>().isActive = false;

    //ゲームオーバー画面のキャンバスを生成
    Instantiate(gameOverCanvasPrefab, transform.position, Quaternion.identity);

    //ボタンのコンポーネントを取得
    Button retryButton = GameObject.Find(retryButtonName).GetComponent<Button>();
    Button titleButton = GameObject.Find(titleButtonName).GetComponent<Button>();

    //ボタンに、クリックしたときの処理を登録
    retryButton.onClick.AddListener(() => moveSceneManager.MoveToScene(moveSceneManager.CurrentSceneNum));	//リトライなので、今と同じシーンを再読み込み
    titleButton.onClick.AddListener(() => moveSceneManager.MoveToScene(0));	//タイトル画面に戻るので、シーン番号は0番
  }

}

変更内容はコメントを読んで頂ければわかると思いますが、大まかにいうと

  • 変数の初期化メソッドの追加
  • クリア・ゲームオーバー処理用のメソッドの追加
  • (ついでに)コインの枚数に関係する変数の追加

を行っています。

ちなみにクリア・ゲームオーバー処理用メソッドでは、キャンバス(※次回作ります)を生成してその中のボタンを検索し、そのボタンにメソッドを登録する、といった処理をしています。

MoveSceneManagerの変更

次に、シーンの読み込みを担当しているMoveSceneManagerのスクリプトを少しだけ変更します。「OnSceneLoaded」というメソッドを次のように変更してください。

//省略

//シーンのロード時に実行(最初は実行されない)
protected virtual void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
  gameManager.InstantiateWhenLoadScene();
  gameManager.InitGame();	//追加
}

//省略

シーンのロード時にGameManagerのいくつかの変数を初期化したいので、このような処理を追記しました。

プレイヤーの変更

ここまでできたら、最後にプレイヤーキャラに少し手をくわえます。

アニメーターコントローラーの変更

まず、プレイヤーの「やられ時」のアニメーターの状態をまだ作っていなかったのでここで作ります。下の図のように「Dead」という名前のBool型のパラメーターを作り、Player_Deadステート(※アニメーションはダメージステートと同じでOKです)を作ったら「Any State」から遷移するようにしましょう。

やられ状態の追加

PlayerControllerの変更

そうしたら、PlayerControllerスクリプトも少し変更しておきます。スクリプトを下記のように変更してください(※適宜省略してあります)。「追加その2」または「変更」と書かれた部分が該当箇所です。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(SpriteRenderer))]
[RequireComponent(typeof(Animator))]
public class PlayerController : BaseCharacterController
{

  //省略
    
  protected override void Damage()
  {
    //既にダメージ状態(=無敵時間中)なら終了
    if (damage)
    {
      return;
    }

    //ヒットポイントを-1
    //Hpプロパティにより、HPが0になると自動的にDead()が呼ばれる(※BaseCharacterController参照)
    Hp--;

    if(Hp > 0)
    {
      StartCoroutine("DamageTimer");
    }
    else
    {
      //追加その2
      Dead();
    }
  }

  //省略

  protected override void Dead()
  {
    isActive = false;
    animator.SetBool("Dead", true); //変更

    //追加その2
    rigidBody2D.velocity = Physics2D.gravity / rigidBody2D.gravityScale;
    gameManager.GameOver();
  }

  //省略

}

変更点は、

  • ダメージを受けた時にHPが0以下ならDeadメソッドを呼ぶようにした
  • DeadメソッドではアニメーターがDeadステートになるようにして、GameManagerのゲームオーバー処理を呼ぶようにした

といった感じですね。これでクリア・ゲームオーバー処理を行うための変更作業が一通り完了しました。


次のページ→クリア&ゲームオーバー処理の作り方(2):キャンバスの作成