タイトル画面とゲームオーバー画面を作りましたが、ゲームオーバーのシーンに遷移する処理を作っていませんでした。未だに自機は無敵ですし。
ゲームオーバーのシーンに遷移する
自機がダメージを受けるようにする
自機がダメージを受けた場合の処理を考えます。
- 残機を減らして、残機がなくなったらゲームオーバー
- エネルギーを減らして、エネルギーがなくなったらゲームオーバー
今回は伝統的なシューティングゲームの形である残機を減らす処理について考えます。
public void playerDamaged()
{
if (GameData.gameState == GameState.Playing) // 通常プレイ中なら
{
GameData.gameState = GameState.PlayerDamaged; // ゲーム状態をPlayerDamagedに変更
PlayerDamageTimer = 300; // 無敵時間をリセット
if (GameData.playerLife > 0) // プレイヤーのライフが残っている場合
{
GameData.playerLife--; // ライフを1減らす
}
else
{
GameData.gameState = GameState.GameOver; // ライフが0になったらゲームオーバー状態に変更
}
}
}
この関数は、プレイヤーの残機を一つ減らし、残機がなくなったらゲームオーバーに移行します。ただ、残機を一つ減らすだけでもいいですが、被弾したことが分かるように無敵時間を設定したいです。そこで、無敵処理中は別の処理をするために、状態を設定します。
状態を定義する
using UnityEngine;
public enum GameState // ゲーム中の状態を定義
{
Title, // タイトル画面
Playing, // ゲームプレイ中
Pause, // 一時停止中
PlayerDamaged, // プレイヤーがダメージを受けた状態
GameOver // ゲームオーバー状態
}
public static class GameData
{
public static GameState gameState; // ゲームの状態
public static int score; // ゲームのスコア
public static int playerLife; // プレイヤーのライフ
}
enumでGameStateという型を作ります。GameStateは状態を表します。GameState.TitleやGameState.Playingという状態に変化します。GameDataの中にgameStateという変数を作り、ここに状態を保持します。どのスクリプトからでもGameData.gameStateでアクセスできます。これで、状態を保持する仕組みが出来ました。次に、状態によって処理を分ける部分を作ります。
void Update()
{
timer++;
switch (GameData.gameState)
{
case GameState.Playing:
// ゲームがプレイ中の処理
break;
case GameState.PlayerDamaged:
// プレイヤーが被弾したときの処理
break;
case GameState.GameOver:
// ゲームオーバーの処理
break;
default:
break;
}
ScoreText.text = GameData.score.ToString();
if (timer > timerMax) timer = 0;
}
規模が大きいゲームになるとswitchを使うと大変になるんだそうですが、今回はこれでいきます。
ゲームがプレイ中の処理
// ゲームがプレイ中の処理
if (timer == 10)
{
Instantiate(Enemy01, new Vector3(Random.Range(-10f, 10f), 6f, 0f), Quaternion.Euler(0, 0, 180));
}
else if (timer == 20)
{
Instantiate(Enemy02, new Vector3(-12f, 2f, 0f), Quaternion.Euler(0, 0, -140));
}
else if (timer == 30)
{
Instantiate(Enemy03, new Vector3(Random.Range(-10f, 10f), 6f, 0f), Quaternion.Euler(0, 0, 180));
}
else if (timer == 40)
{
Instantiate(Enemy04, new Vector3(Random.Range(-10f, 10f), 6f, 0f), Quaternion.Euler(0, 0, 180));
}
これは、今までのUpdate関数の中身をそのまま移しました。
自機がダメージを受けたときの処理
// プレイヤーが被弾したときの処理
// ここではダメージを受けたことを示すためのタイマーを使用
// PlayerDamageTimerはダメージを受けた後の無敵時間を表す
if (PlayerDamageTimer % 5 < 3)
{
playerInstance.SetActive(false); // プレイヤーを非表示にする
}
else
{
playerInstance.SetActive(true); // プレイヤーを表示する
}
PlayerDamageTimer--;
if (PlayerDamageTimer <= 0)
{
GameData.gameState = GameState.Playing; // 無敵時間が終わったらゲーム状態をPlayingに戻す
playerInstance.SetActive(true); // プレイヤーを再表示する
}
PlayerDamageTimerの初期値は300です。つまり300フレームの間、ダメージ処理になります。ダメージ処理の間は、3フレームで自機を非表示にして、2フレームで自機を表示します。この結果、自機が点滅しているように見えます。ここで重要なのはPlayerではなく、playerInstanceを操作している点です。Playerにはプレイヤーのプレハブがセットされていますので、Playerを非表示にしてもインスタンスは非表示にならないのです。そこで、以下のようにしてPlayerのインスタンスをplayerInstanceにセットします。
public class StageManager : MonoBehaviour
{
//中略
public GameObject Player; // プレイヤーのプレハブをセットする
//中略
GameObject playerInstance; // <--インスタンスを入れる変数を宣言
//中略
int timer = 0;
int PlayerDamageTimer; // 無敵時間を管理するタイマーを宣言
const int timerMax = 40;
void Start()
{
// ゲームの初期状態を設定
GameData.score = 0;
GameData.playerLife = 2; // プレイヤーのライフを初期化
ScoreText.text = GameData.score.ToString();
playerInstance = Instantiate(Player, new Vector3(0, -4.5f, 0), Quaternion.identity);
GameData.gameState = GameState.Playing;
PlayerDamageTimer = 300; // 無敵時間を300フレームに設定
}
GameObject型のplayerInstanceと、int型のPlayerDamageTimerの二つの変数を宣言し、Start関数の中ではゲームの初期化に関する処理を追加しました。自機を生成し、playerInstanceに保持しています。
ゲームオーバーになったときの処理
// ゲームオーバーの処理
UnityEngine.SceneManagement.SceneManager.LoadScene("GameOver"); // GameOverはゲームオーバーのシーン名
ゲームオーバーになったときは、GameOverのシーンを呼び出すだけです。
ゲームオーバーのシーン

ゲームオーバーのシーンは、何もしないとゲームオーバーの画面が永久に表示されるだけです。そこで、五秒経ったらタイトル画面に戻るようにします。以下のスクリプトを作成し、メインカメラに取り付けます。(空のゲームオブジェクトを作って取り付けても良い)
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class GameOver : MonoBehaviour
{
void Start() // ゲームオーバー時に呼び出されるメソッド
{
StartCoroutine(DelayCoroutine(5.0f, () => // 5秒後に中身を実行
{
GotoTitle(); // タイトル画面へ遷移するメソッドを呼び出す
}));
}
private IEnumerator DelayCoroutine(float seconds, UnityAction callback) // 指定した秒数待機してからコールバックを実行するコルーチン
{
yield return new WaitForSeconds(seconds); // 指定した秒数待機
callback?.Invoke(); // コールバックを実行
}
private void GotoTitle() // タイトル画面へ遷移するメソッド
{
// ここにゲームオーバーの処理を追加
UnityEngine.SceneManagement.SceneManager.LoadScene("Title"); // Titleはタイトル画面のシーン名
}
}
これで、ゲームオーバーのシーンが表示されてから五秒後にタイトル画面に戻ります。これで、一通り完成しました。あとは、これをどう作り込んでいくか・・・。
今回はここまでです。お疲れ様でした。
コメント