【Unity/2D】Flappy Bird風ゲームを作ってみる話 #7 ゲームの一時中断の実装

記事をご覧いただき、誠にありがとうございます。

投稿主の無能です。

前回は、土管を一定間隔毎に生成する機能を実装しました。

今回は、ゲームの一時中断についてやっていこうと思います。

ゲームの一時中断について考える

まずはゲームの一時中断について考えてみましょう。
そもそも、どうやったらゲームの進行が止まるのでしょうか。

最初に、現実に流れる時間と、ゲームの中の時間は違うものだという事を思い出してください。
…言われなくても分かってますよね。

ではゲームの中の時間、いつもの言い方だとゲーム内時間ですが、ゲーム開始と同時にストップウォッチで時間を測ったとします。

ストップウォッチで計測している時間を停止する、というのがゲームの一時中断に該当します。

そして再びストップウォッチを動かしてやると、ゲーム内時間が流れます。

また、逆にストップウォッチで流れる時間を早くした場合は、ゲーム内時間も早くなります。

一時停止の理屈としては、この「ゲーム内時間を止める・動かすことで一時停止のような機能を実装する」という内容になります。

理屈は分かったので、どうやって一時中断の機能を呼び出すのか考えましょう。

どのPCでも絶対にあるキーを押したら一時中断の機能を呼び出します。

Functionキーだとキーの切り替えが必要になる場合があるので、ここではEscキーで一時中断、もう一度押すと一時中断の解除、という処理を行うようにします。

一時中断の機能が具体的に見えたので、Unityで実装の準備をします。

一時中断の機能を実装する準備

GameManagerの作成

では一時中断の機能を実装する準備をしましょう。

ゲーム内時間というゲームの根本的なところを操作する機能を付けるオブジェクトをを作るので、名前を「GameManager」とする空のオブジェクトを作成します。

空のオブジェクトを作成

名前を「GameManager」とする

座標がおかしくなっていることがあるので、手入力で修正するか、コンポーネントの名前の右側の詳細メニューのResetで修正します。

座標がおかしくなっているので修正する

コンポーネント右側の詳細メニューのResetで修正

コンポーネントが初期状態に戻った

Resetは該当のコンポーネントを初期状態に戻します。

では次に、新たに「GameManager」スクリプトを作成し、GameManagerオブジェクトにアタッチします。

「GameManager」スクリプトを作成

GameManagerオブジェクトにアタッチ

これでGameManagerの準備が出来ました。

一時停止中のUIを作成

Canvasの追加

では次に、一時停止中であることをゲームのプレイヤーに知らせるためのUIを作っていきましょう。

UI > CanvasでCanvasを作成し、名前を「UI_GameStatus」にします。

UI > CanvasでCanvasを作成

名前を「UI_GameStatus」にする

Panelの追加

Canvasに更にUI > Panelを追加します。

追加したPanelの名前を「UI_GamePause」にします。

Canvasに追加でUI > Panelを追加

名前を「UI_GamePause」にする

TextMeshProの追加

そしてUI_GamePauseにテキストを追加します。

UI > Text - TextMeshProでテキストのオブジェクトを追加し、名前を「Text_GamePause」にします。

UI_GamePauseにUI > Text - TextMeshProでテキストのオブジェクトを追加

TextMeshProの初回の使用の場合は、別ウィンドウが表示されます。

機能の追加が必要なのでImport TMP Essentialsボタンを押してください。

Import TMP Essentialsボタンを押す

これでTextMeshProで文字を表示する機能が整いました。

アクティブなボタンが変わって「Import TMP Examples & Extras」に切り替わりますが、不要なため無視してウィンドウを閉じて大丈夫です。

アクティブなボタンが切り替わるが無視してウィンドウを閉じる

Legacyでも問題ありませんが、これからスタンダードになっていくであろう方に使い慣れておきたいので、TextMeshProを選択します。

Legacyで良いという方はLegacyを使ってください。

追加したテキストオブジェクトの名前を変更します。

「Text_GamePause」にリネーム

今の状態だとUI_GamePauseと同じ階層になっているので、ドラッグしてUI_GamePauseの子オブジェクトにします。

ドラッグしてUI_GamePauseの子オブジェクトにする

TextMeshProは日本語のフォントを用意して、Font Asset Creatorで所謂日本語のゴム印を作成する必要があります。

ちょっと面倒なので、今回は英語での対応にします。
…英語苦手だけど、Google翻訳があるさって事でw

Imageコンポーネントの調整または削除

今の状態でGameビューを見ると、摺りガラスを通して画面を見ているような状態になっています。

これはPanelに付いているImageコンポーネントの影響によるものです。

Panelに付いているImageコンポーネントの影響により摺りガラスを通して画面を見ているような状態

これを解消するには、Imageコンポーネントを削除するか、Imageの色の部分を選択して色相環を表示し、色相環のアルファ値を0にすれば大丈夫です。

Imageコンポーネントを削除する

または色相環のアルファ値を0にする

先程の状態が解消された

一時中断のUIの作成

ではText_GamePauseを中央よりやや上に設置します。

そして一時中断なので、テキストを「Pause」にしてやります。

文字の大きさ、配置などは画像を参考にして、お好きに調整してください。

Rect Transform

Text

Gameビュー

テキストが表示されました。

この一時中断のUIは常時表示するものでは無く、Escキーで一時中断になった場合にだけ表示され、一時中断を解除したら消えるようにします。

という事はスクリプトからUIの表示・非表示を行うので、UI_GamePauseパネルを非アクティブにしておきます。

UI_GamePauseパネルを非アクティブにする

これで準備が出来たので、スクリプトを書いていきましょう。

一時中断の機能をスクリプトに書く

ではスクリプトを書いていきます。

GameManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    #region Var-GamePause
    [Header("一時中断のUI")]
    [SerializeField] GameObject UI_GamePause;
    #endregion

    #region Var-Internal
    const float timeScaleReset = 1f;                                // TimeScaleのリセット用
    bool isPause = false;                                           // 一時中断のフラグ
    #endregion

    #region Update
    void Update()
    {
        // Escキーが押された場合
        if (Input.GetKeyDown(KeyCode.Escape))
        {
            // 一時中断のフラグがfalseの場合
            if (!isPause)
            {
                // ゲームを一時中断する
                GamePause();
                // 一時中断のUIをアクティブ
                UI_GamePause.SetActive(true);
                // 一時中断フラグをtrue
                isPause = true;
            }
            // それ以外の場合
            else
            {
                // 一時停止を解除する
                GamePauseRelease();
                // 一時中断のUIを非アクティブ
                UI_GamePause.SetActive(false);
                // 一時中断フラグをfalse
                isPause = false;
            }
        }
    }
    #endregion

    #region GamePause
    // ゲームを一時中断する
    void GamePause()
    {
        // タイムスケールを0にする
        Time.timeScale = Variables.zero;
    }
    #endregion

    #region GamePauseRelease
    // 一時停止の解除
    void GamePauseRelease()
    {
        // タイムスケールを戻す(1にする)
        Time.timeScale = timeScaleReset;
    }
    #endregion
}
それでは見ていきましょう。

メンバ変数

はじめにメンバ変数から見ていきます。

まず一時中断を表示するパネルのUI_GamePauseです。

何故PanelじゃなくてGameObjectとして取得するのかというと、SetActiveでアクティブ・非アクティブにするためです。

変数の取得の仕方でオブジェクトの振る舞いも変わってくるので注意しましょう。

次に定数のfloatのtimeScaleResetです。

これはゲーム内時間であるTimeScaleを、一時中断を解除する際に元に戻す役割があります。

そして一時中断のフラグとなるboolのisPauseです。

これでメンバ変数は以上です。

Update関数

次にUpdate関数を見ていきます。

Update関数ではEscキーが押された場合の処理になります。

プレイヤーのキー入力受付と同じですね。

相違点はGetKeyDownで、キーストロークが終わる、つまりEscキーが押されて離されたという一つのストロークが終了して、はじめてカッコ内の処理へと移ります。

この違いは以前の説明の通りです。

そしてEscキーが押された場合、もう一つ条件分岐があります。

一時中断のフラグがfalseの場合は、GamePause関数を呼び出し、一時中断のUIをアクティブにします。

そして一時中断のフラグをtrueにします。

そしてそれ以外の場合、つまり一時中断のフラグがtrueの場合は、一時中断のフラグがfalseの場合と逆の処理をしてやります。

Update関数はこれで以上です。

GamePause関数・GamePauseRelease関数

ではGamePause関数・GamePauseRelease関数を見ていきます。

GamePause関数はゲーム内時間の流れを0にしています。

逆にGamePauseRelease関数は、0になったゲーム内時間の流れを1に戻します。

因みにTimeScaleはEdit > Project Settings内でTimeの項目で確認できます。

TimeScaleのデフォルト値は1で、これがゲーム内時間の流れになります。

Edit > Project Settings内のTimeの項目で確認できる

これでGameManagerスクリプトは以上です。

動作確認

では動作確認前の準備をします。

GameManagerオブジェクトのInspectorビューに項目が追加されているので、UI_GamePauseパネルを設定します。

追加された項目にUI_GamePauseパネルを設定

では準備ができたので動作確認していきます。

Escキーが押されたら一時中断されました。

Escキーが押されたら一時中断された

再度Escキーが押すと、通常通りゲームが動きました。

再度Escキーが押すと通常通りゲームが動く

これで一時中断の機能が実装出来ました。

まとめ

今回は
  • GameManagerを作成した
  • 一時中断のUIを作成した
  • スクリプトで一時中断の機能を実装した
という事をやりました。

次回は、ゲームオーバー時の処理についてやっていこうと思います。

では、また次回!

コメント