前回までで敵やコインを作ったので、これでゲームをクリアしたりゲームオーバーになったりする要素がそろいました。
そこで、ここからはステージクリア処理とゲームオーバー処理を作っていきます。主な作業内容は次の2つです。
- GameManager等のスクリプトの変更
- クリア・ゲームオーバー画面用のキャンバスの作成
まず、ここでは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のゲームオーバー処理を呼ぶようにした
といった感じですね。これでクリア・ゲームオーバー処理を行うための変更作業が一通り完了しました。