こんにちは、ともくんのゲーム作り部屋にようこそ!
このページでは、Unityを使った2Dシューティングゲームの作り方の10回目として、リトライシーンの作成とリトライ位置を変更する処理について紹介しています。
前回、ゲームマネージャーを作ってスコアやライフを管理する仕組みを作りました。
今度は、敵からダメージを受けてリトライする際の処理で、新たにリトライシーンを作成して一度そのシーンに遷移させてから、メインシーンに戻す仕組みを作っていきます。
また現状は、どこでダメージを受けても最初の地点に戻ってしまうので、このリトライで戻った時の座標も変更させていきたいと思っています。
そこで、新たにリトライシーンを作成して、リトライポイントでスタート地点を変えていく処理までをまとめていきます。
リトライ用のシーンを作成する
まずは、リトライ用に別のシーンを作りたいので、新しくシーンファイルを作成します。
シーンファイルを作成する際は、メニューバーの「File」から「New Scene」を押して、

シーンを作成するテンプレートを選んで「Create」を選択します。

ここでは、メインシーンと同じ2Dでリトライシーンを作成するので、「Basic 2D」を選択しています。
シーンが作成できたら、シーン名を付けて保存しておきたいので、メニューバーの「File」から「Save As…」を選択します。

今回は、「RetryScene」というシーン名で、「Scenes」フォルダの中に保存しています。

ここまでできたら、リトライシーンの中身を作成していきますが、基本的にはメインシーンと同じように作成していけば問題ありません。
今回は、リトライシーンの作成の細かい部分は紹介しませんが、メインシーンと同じく「GameManager」を置いて、ライフ数の表示もメインシーンで作成した「LifeDisplay」のスクリプトを使って、残りのライフ数が自動的に反映されるようにしています。


GameManagerについては、前回の作り方の9回目の記事で解説していますので、参考にしてみてください。
リトライシーンの作成ができたら、この画面からメインシーンに遷移させる処理を作ります。
今回シーンを遷移させる処理は、UIにアタッチしている「RetryText」というスクリプトの中に書いています。
using TMPro; // TextMeshProを使うのに必要
using UnityEngine;
using UnityEngine.SceneManagement; // LoadSceneを使うのに必要
public class RetryText : MonoBehaviour
{
public GameObject readyText; // UIのテキストのオブジェクトを取得
float time = 0.5f; // 秒数を指定
float delta = 0; // 加算用の変数を宣言
bool isChanged = false; // テキストが変更されたかどうかをチェックする変数
void Update()
{
this.delta += Time.deltaTime; // フレーム間の差を加算
if (this.delta > this.time) // timeの値を上回った場合
{
if (readyText.activeSelf == false) // テキストが非アクティブ状態の場合
{
readyText.SetActive(true); // アクティブ状態に変更
this.delta = 0; // deltaを0にリセット
time = 0.7f; // 秒数を0.5から0.7に変更
}
else if (isChanged == false) // テキスト変更されていない場合
{
readyText.GetComponent<TextMeshProUGUI>().text = "GO!!"; // テキストの中身を変更する
isChanged = true; // 変数にtrueを入れる
this.delta = 0; // deltaを0にリセットする
time = 0.3f; // 秒数を0.7から0.3に変更
}
else
{
SceneManager.LoadScene("MainScene"); // メインシーンに遷移させる処理
}
}
}
}
リトライシーンの処理が終わる32行目で、SceneManagerクラスのLoadSceneメソッドの引数に、「MainScene」を指定してメインシーンに切り替える処理を行っています。
これでリトライシーンからの遷移ができたので、次はメインシーンからリトライシーンへの遷移を設定します。
メインシーンでは、RetryDirectorでリトライ処理を行っていたので、このスクリプトに変更を加えていきます。
using UnityEngine;
using UnityEngine.SceneManagement; // LoadSceneメソッドを使うのに必要
public class RetryDirector : MonoBehaviour
{
GameObject player; // playerを参照する
void Start()
{
player = GameObject.Find("player"); // playerのオブジェクトを取得する
}
void Update()
{
if (player.activeSelf == false) // playerのステータスが「非アクティブ」の場合
{
SceneManager.LoadScene("RetryScene"); // シーンを読み込んでリトライする
}
}
}
17行目のLoadSceneメソッドの引数に、「RetryScene」を指定してリトライシーンへの遷移処理を行います。
これで、スクリプト側でのシーン切り替えの処理が完了しましたが、シーン遷移はプロジェクトにシーンを指定しないと切り替えが行われません。
シーンを指定する方法は、メニューバーの「File」から「Build Profiles」を選択します。

Build Profilesが開いたら、「Scene List」を選択してシーンファイルをドラッグ&ドロップしてきます。

シーン番号を設定することができるので、ここではMainSceneを0、RetrySceneを1で設定しています。

これで実際にゲームを実行してみると、

ダメージを受けるとリトライシーンに遷移して、その後メインシーンに切り替わる処理ができました。
リトライの位置をゲームマネージャーで管理する
現在は、どこでダメージを受けてもリトライのスタート地点は、一番最初に戻ることになっていますが、これをある特定の地点まで進んだら、リトライのスタート地点を変えるように設定していきます。
リトライが発生するとシーン遷移が行われることになるので、シーンが遷移されても消去されないゲームマネージャー(GameManager)でスタート位置を決める変数を管理していきます。
using UnityEngine;
public class GameManager : MonoBehaviour
{
public static GameManager instance; // 静的なGameManagerのインスタンスを作成
public int lifeCount; // ライフの数を計算する変数
public int scorePoint; // スコアの数を計算する変数
public int startPos; // スタート位置を決める変数
void Awake() // Startメソッドよりも早く処理される
{
if (instance == null) // インスタンスの中身が無い場合
{
instance = this; // インスタンスの中身を入れる
DontDestroyOnLoad(this.gameObject); // シーンが読み込まれても削除されないようにする
}
else
{
Destroy(gameObject); // GameManagerを削除する
}
}
}
ここでは、GameManagerの8行目でstartPosという変数を宣言して、この変数でスタート位置を管理していきます。
次に、今回のゲームでは、ステージ自体を動かしているので、スタート位置を決める処理はステージを動かすスクリプトであるStageControllerに書いていくことになります。
using UnityEngine;
public class StageController : MonoBehaviour
{
public float stageSpeed = 0.03f; // ステージの速さを決める変数
public GameObject[] startPos; // スタートの位置を決めるオブジェクトの配列
void Start()
{
transform.Translate(0, -startPos[GameManager.instance.startPos].transform.position.y, 0); // スタート位置に移動させる処理
}
void Update()
{
transform.Translate(0, -stageSpeed, 0); // ステージの座標を動かす処理
}
}
まず6行目に、GameObject型の配列を作って、この中にスタート位置を決めたオブジェクトを後ほど入れていきます。
10行目のStartメソッドの中で、transform.Translateを使ってステージを動かしてスタート位置を変更しています。
X軸の横座標は真ん中に表示させたいので0を指定して、Y軸にGameManagerで宣言した変数startPosを配列の[]の中に設定してあげることで、ステージをその配列で指定したオブジェクトの地点まで動かすという処理を行っています。
これでスクリプトは完了しましたが、GameObject型の配列には、まだ何もオブジェクトが入っていません。
スタート位置を指定するための空オブジェクトを作って、それぞれをスタートさせたい位置に移動させていきます。




ここでは、startPos_0、startPos_1、startPos_2、startPos_3という空オブジェクトで4つ作成しました。
次に、これらのオブジェクトを配列に入れていきたいので、stageのオブジェクトを選択してインスペクターウィンドウのStageControllerの項目から、Start Posの+ボタンで配列を4つ作成して、それぞれのオブジェクトをドラッグ&ドロップしていきます。

これで、オブジェクトに配列を入れることができたので、一度スタート位置が変わるかどうかを試してみます。
なお、テストする際は、GameManagerを選択してインスペクターウィンドウから、Start Posの値を0から別の数字に変更するのが簡単です。


ゲームを開始すると、ちゃんとスタート位置が変わっていて大丈夫そうなので、Start Posの値を0に戻しておきます。
リトライポイントを作る
リトライのスタート位置を設定することができたので、次はリトライポイントを設定して、GameManagerで決めたstartPosの変数を更新させていきます。
リトライポイントは、透明なオブジェクトを作って、プレイヤーと当たったら変数を更新させるという形で作っていきます。
まずは、ヒエラルキーウィンドウから「2D Object」の「Sprites」にある「Square」を押して、四角いオブジェクトを作成します。

この四角のオブジェクトをゲーム画面に合わせて横長に変形させて、リトライポイントを作りたい場所に移動させておきます。

ここでは、「retryPoint_1」というオブジェクト名にしています。
このオブジェクトを透明にさせたいので、インスペクターウィンドウのColorの項目から、

Aの値を0に変更してあげることで、完全に透過して透明なオブジェクトになります。

また、このオブジェクトはプレイヤーと当たり判定を行いたいので、Box Collider 2Dコンポーネントを付けて、「Is Trigger」にチェックを入れて通り抜けるようにしておきます。

ここまでできたら、このオブジェクトをコピーして、他のリトライポイントの場所ににセットしておきます。
ここでは、3つのリトライポイントを作成しました。

このリトライポイントのオブジェクトは、ステージと一緒に動かしてあげる必要があるので、stageオブジェクトの子オブジェクトに入れておきます。

あとは、このリトライポイントにプレイヤーが触れたら、startPos変数を更新させる処理を書いていきます。
リトライの位置を決める「RetryPointer」というスクリプトを作成して、プレイヤーにアタッチしておきます。

using UnityEngine;
public class RetryPointer : MonoBehaviour
{
public GameObject[] retryPoint; // リトライポイント用の配列を宣言
void OnTriggerEnter2D(Collider2D collision) // 当たり判定があった場合
{
if (collision.gameObject == retryPoint[0]) // オブジェクトが0の場合
{
GameManager.instance.startPos = 1; // 変数を1に更新する
}
else if (collision.gameObject == retryPoint[1]) // オブジェクトが1の場合
{
GameManager.instance.startPos = 2; // 変数を2に更新する
}
else if (collision.gameObject == retryPoint[2]) // オブジェクトが2の場合
{
GameManager.instance.startPos = 3; // 変数を3に更新する
}
}
}
5行目で、GameObject型の配列retryPointを宣言して、後ほどインスペクターウィンドウからリトライポイントを設定していきます。
7行目以降で、OnTriggerEnter2Dメソッドを使ってプレイヤーとリトライポイントが当たった際の処理を指定していきます。
その中で、それぞれのリトライポイントごとに、GameManagerのstartPos変数を書き換える処理を書いています。
スクリプトが作れたら、配列にオブジェクトを入れるため、プレイヤーを選択してインスペクターウィンドウのRetryPointから+ボタンで配列を3つ作り、それぞれに対応するリトライポイントをドラッグ&ドロップで指定してあげます。

これですべての設定が完了したので、実際にゲームを動かしてみます。
リトライポイントを過ぎて、ダメージを受けた場合、ちゃんとスタート地点を変更することができました。
まとめ
このページでは、リトライシーンとリトライの位置を変更する処理を作っていきました。
リトライの位置を決める場合は、ライフやスコアと同じくゲームマネージャーを使うことで、シーン遷移に関係なく変数を保持してくれます。
リトライポイントの作り方は他にもあると思いますが、良かったら参考にしてみてください。
次は、シューティングゲームでよくあるアイテムでプレイヤーを強くする設定を作っていきます。
最後までお読みいただきまして、ありがとうございました!
コメント