【Unity実践】#9 プロトタイプ編 ~ シーンの制御 part1 ~【Boxゲーム】
今回の内容
今回からはシーンの制御の仕組みを作成します。
クリア後に次のステージへ遷移する、ゲームオーバー時にリトライするといった機能を実装していきます。
改めての注意書きとなりますが、ステージ遷移関連の仕組みは実際のゲームで実装している仕組みとは異なっています。
ここで紹介するのは実装方法の1例として見て頂ければと思います。
※初めての方はこちらから
⇒ 【第1回記事】この連載について
シーン制御の設計
いきなりスクリプト作成に入る前に、今回のシーン制御の仕様を簡単に整理します。
「GameScene」+「ステージ番号」
例)GameScene1, GameScene2, …
1周目は順番に選択、2周目以降はランダムとする。
例えば10ステージあるとき、
▼ステージ1-10
GameScene1
GameScene2
GameScene3
…
GameScene10
▼11以降
全シーンの中からランダムで選択
PlayerPrefsを使って管理する。
その際、以下の2つのパラメータを使用。
・StageNum ⇒ 現在何ステージ目かを管理
・SceneNum ⇒ 読み込むシーンの番号を管理(GameScene1の「1」の箇所)
なぜ2つ用意しているかと言うと先ほどの2の仕様関連で、
1周目は「読み込むシーン番号(SceneNum)= 現在のステージ数(StageNum)」となるが、
2周目以降は両者がズレて行くので、別々のパラメータで管理することとしています。
上記3つの仕様を前提として、この後の実装を進めていきます。
シーンを読み込む
新規スクリプトを追加して、名前は「StageControllerScript」としましょう。
まずは以下を記述します。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; public class StageControllerScript : MonoBehaviour { public const string GAME_SCENE_NAME = "GameScene"; // シーン名のプレフィクス public const int GAME_SCENE_COUNT = 1; // シーンの数 private int stageNum; // 現在のステージ数 public Text stageName; // 現在のステージ名("Stage" + stageNum) void Start() { // ステージ数(画面表示用 ※実際のシーン名とは必ずしも対応しない!) stageNum = PlayerPrefs.GetInt("StageNum", 1); stageName.text = "Stage" + stageNum; // 自分のシーンではない場合、ロードし直す if (GetLoadSceneName() != SceneManager.GetActiveScene().name) { LoadScene(); } } void Update() { } // ロードするシーン名を取得 private string GetLoadSceneName() { int loadSceneNum = PlayerPrefs.GetInt("SceneNum", 1); return GAME_SCENE_NAME + loadSceneNum; } // ステージを読み込む処理(現在のstageNumに対応するステージ) private void LoadScene() { SceneManager.LoadScene(GetLoadSceneName()); } }
記述ができたら、シーンに空のオブジェクトを配置して名前を「StageController」としましょう。
このオブジェクトに、StageControllerScript をアタッチしてください。
さらにインスペクタービューで、StageName に Canvas > StageName をドラッグして下さい。
この Canvas > StageName って何だったかと言うと、第2回目の記事で作成した、
画面の上部に表示するステージ名のUIでした。
順に解説していきます。
9, 10行目:定数の定義
それぞれ定数を定義しており、内容はソース内コメントの通りです。
シーンの数は現在は1としていますが、今後ステージを増やしたときにはここを直接変更します。
12, 13行目:プロパティの定義
こちらは通常のプロパティとして定義しており、内容はやはりコメントの通りです。
StageNum は先ほどの仕様3.の PlayerPrefs と対応するプロパティです。
15~26行目:Startメソッド
はじめに18行目で、現在のステージ数(StageNum)を PlayerPrefs から取得しています。
取得した番号と「Stage」の文字列を結合して、StageName の text プロパティに設定しています。
StageName は画面上部の UI だったので、ここでその表示を設定している形となります。
Startメソッド内の最後にある、22~25行目の処理ですが、
現在のシーンが本来読み込むシーンではない場合に、正しいシーンを読み込み直す処理となっています。
タスクキル等でアプリを終了・再開すると GameScene1 が読み込まれてしまうため、
PlayerPrefs を参照して正しいステージを読み直しています。
34~38行目:GetLoadSceneNameメソッド
その時点で読み込むべきシーン名を取得するメソッドを作成しています。
読み込むシーンの番号は、PlayerPrefs の SceneNum で管理しています。(仕様の3つ目)
この処理は複数の箇所で実行される想定のもと、メソッドとして作成しました。
(現状だと22行目と43行目で使用しています。)
41~44行目:LoadSceneメソッド
シーンを読み込む処理をメソッド化しています。
=====
この後もスクリプトを追記していきますが、まずはここまでの処理を理解してください。
特に大事なことは、以下の2点です。
・LoadSceneメソッドを呼び出すとその時点で読み込むべきシーンが読み込まれる
・読み込むシーンの番号は、PlayerPrefs の SceneNum で管理している
クリア、ゲームオーバーの制御
続いて、クリアやゲームオーバーと言ったゲームの状態を管理するための機能を追加していきます。
まずやることは大きく2つで、
・フラグを追加(クリア、ゲームオーバーそれぞれ)
・フラグの状態によって、UIの表示を切り替える(クリアUI、リトライUIを表示)
ひとまずはここまでを作成します。
StageControllerScript に以下を追加してください。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; public class StageControllerScript : MonoBehaviour { public const string GAME_SCENE_NAME = "GameScene"; // シーン名のプレフィクス public const int GAME_SCENE_COUNT = 1; // シーンの数 private int stageNum; // 現在のステージ数 public Text stageName; // 現在のステージ名("Stage" + stageNum) public static bool isClear; // クリアフラグ public static bool isGameOver; // ゲームオーバーフラグ public GameObject clearCanvas; // クリア時のUI public GameObject retryCanvas; // ゲームオーバー時のUI void Start() { // ステージ数(画面表示用 ※実際のシーン名とは必ずしも対応しない!) stageNum = PlayerPrefs.GetInt("StageNum", 1); stageName.text = "Stage" + stageNum; // 自分のシーンではない場合、ロードし直す if (GetLoadSceneName() != SceneManager.GetActiveScene().name) { LoadScene(); } // 初期化 isClear = false; isGameOver = false; } void Update() { // クリアしたとき if (isClear) { ShowClearCanvas(); enabled = false; } // ゲームオーバーのとき else if (isGameOver) { ShowRetryCanvas(); enabled = false; } } // クリアUIを表示する private void ShowClearCanvas() { clearCanvas.SetActive(true); } // リトライUIを表示する private void ShowRetryCanvas() { retryCanvas.SetActive(true); } // ロードするシーン名を取得 private string GetLoadSceneName() { int loadSceneNum = PlayerPrefs.GetInt("SceneNum", 1); return GAME_SCENE_NAME + loadSceneNum; } // ステージを読み込む処理(現在のstageNumに対応するステージ) private void LoadScene() { SceneManager.LoadScene(GetLoadSceneName()); } }
追記ができたら、インスペクターから
ClearCanvas に Canvas > Clear
RetryCanvas に Canvas > Retry
をそれぞれ設定します。
では追記したスクリプトを見ていきましょう。
ポイントは、「isClear」「isGameOver」の2つのゲーム状態を管理する変数です。
追加した処理、各メソッドはこの2つに関連して動く事となり、
isClear が true ⇒ ShowClearCanvas(クリア時UIが表示される)
isGameOver が true ⇒ ShowRetryCanvas(リトライ時UIが表示される)
となっています。
ここまでできるとシーン制御の完成まであと一歩で、残りの実装としては、
・クリア画面で Nextボタンをタップすると次のシーンを読み込む
・リトライ画面で Retryボタンをタップすると現在のシーンを読み込む
これらの処理を作成するのみとなります。
今回の記事ではこの実装まではせず、次回紹介していくのですが、
実装方法としては先に作成した LoadSceneメソッド や PlayerPrefs の SceneNum を利用します。
宿題がてら、少し実装方法を考えてみて頂くと良さそうです。
デバッグUIの制御
デバッグUIの表示切替も、StageControllerで管理するようにします。
StageControllerScript に以下を追加してください。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.UI; public class StageControllerScript : MonoBehaviour { public const string GAME_SCENE_NAME = "GameScene"; // シーン名のプレフィクス public const int GAME_SCENE_COUNT = 1; // シーンの数 private int stageNum; // 現在のステージ数 public Text stageName; // 現在のステージ名("Stage" + stageNum) public static bool isClear; // クリアフラグ public static bool isGameOver; // ゲームオーバーフラグ public GameObject clearCanvas; // クリア時のUI public GameObject retryCanvas; // ゲームオーバー時のUI // デバッグ用 private bool isDebug = true; // デバッグフラグ public GameObject debugCanvas; // デバッグメニューのUI void Start() { // ステージ数(画面表示用 ※実際のシーン名とは必ずしも対応しない!) stageNum = PlayerPrefs.GetInt("StageNum", 1); stageName.text = "Stage" + stageNum; // 自分のシーンではない場合、ロードし直す if (GetLoadSceneName() != SceneManager.GetActiveScene().name) { LoadScene(); } // 初期化 isClear = false; isGameOver = false; // デバッグモード表示の切り替え debugCanvas.SetActive(isDebug); } // 以下省略
クリアやリトライと同様に、DebugCanvasに Canvas > Debug を設定しましょう。
デバッグUI の Retryボタンや Clearボタンをタップした時の処理も次回作成しますが、
実装方法としてはクリア画面やリトライ画面と同様になるので、こちらも宿題がてら考えてみて下さい。
また、まだしばらくはデバッグUI は表示したままとしますので、isDebug の値は true としておきます。(22行目)
おわりに
今回はシーン制御の実装の1回目と言うことで、ボタンを押す手前までの処理を作成しました。
目に見えない箇所の作成だったことと PlayerPrefs等の設計に絡んだ実装がやや難易度が高めかと思いますので、
理解できるまでじっくり読んでみて下さい。
次回は各種ボタンとの関連付けを行って、シーン制御の機能が完成する予定ですのでお楽しみに!
連載目次リンク
関連する連載リンク
© Unity Technologies Japan/UCL