ゲーム制作   Unity ソフトウエア 

Unity ソフトウエアでゲーム制作#1モグラたたき編(24.Buttonでポーズ再開リトライ)

キャッチ画像モグラたたきButtonとポーズ再開リトライ機能

本投稿は2024年9月時点の内容になります。アップデートにより変更となる場合があります。また環境によって違いがあると思いますのであくまで参考として、ご了承ください。

様々な書籍、ブログや動画を参考にさせていただきました。多すぎて一つ一つはtお紹介できませんが感謝です。

初心者の自分がUnity ソフトウエアでゲームを作ってみました。とりあえずシンプルなものということでモグラたたきに挑戦です。ゲーム作ってみるかという感じになったときに、いいタイミングで某ゲームのイベントシナリオ内ミニゲームにモグラたたきが実装されていたのでUIとかエフェクトとか、諸々の仕様をぱくって参考にして作ってみましたよ。様々なHowToの中の選択肢のひとつとして、同じ初心者さんの参考になればよいです。

\ チェック /

今回も必須です。Buttonを使って一時停止(ポーズ)を実装します

今回はポーズ機能を実装します。ボタンをクリックすると一時停止するようにします。

本記事のポイント

  • Buttonの使い方
  • 一時停止と再開の実装例
  • リトライ機能の実装

一時停止(ポーズ)を実装するための準備

一時停止ポーズは簡単です。timescaleを0にするだけです。早速作っていきましょう。

ポーズ機能に使う素材を用意します。

一時停止(ポーズ)の実装例(その1オブジェクトの準備)

  1. 今回必須なのは以下の4つです。
  2. 一時停止ポーズするためのボタン「PauseButton」(UI>画像で作成)
  3. 開いたUIを閉じるボタン「CloseIcon」(UI>画像で作成)
  4. リトライするボタン「RetryButton」(UI>ボタン-TextMeshProで作成)
  5. ゲームのホーム(未実装)に戻る「QuitButton」(UI>ボタン-TextMeshProで作成)
  6. 参考に上記画像のようにレイアウトしました。あくまで参考なので前回までに使ったTextMeshPro、CanvasGroupやアニメーションなどを使って自由に装飾、演出してみてください。
  7. アニメーションを付けた場合は「更新モード」>「スケールされていない時間」にするのを忘れないように。(こちらを参考に

\ TextMeshProについてはこちらをチェック /

UIを開閉するスクリプトの準備

一時停止(ポーズ)の実装例(その2-1UIを開閉するスクリプトの準備①)

  1. スクリプト「UIController」クラス作成
  2. 以下のようにしました。
class UIController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UIController : MonoBehaviour
{
    //UIを開く
    public void OpenUI()
    {
        //表示をActiveに
        gameObject.SetActive(true);
    }

    //UI閉じる
    public void CloseUI()
    {
        //表示を非Activeに
        gameObject.SetActive(false);
    }
    //UIの初期化
    public virtual void InitUI()
    {
        //表示を非Activeに
        gameObject.SetActive(false);
    }

    private void Start()
    {
        //初期化
        InitUI();
    }
    
//    今回ハマった初期化
//    private void OnEnable()
//    {
//        InitUI();
//    }
}

スクリプトざっくり解説

  • シンプルにSetActiveでUI表示をON/Offしています。
  • (21)継承先で自身を「GameManager」に渡す処理を加えたいので、overrideするためにvirtualにしています。

一時停止(ポーズ)の実装例(その2-2UIを開閉するスクリプトの準備②)

  1. スクリプト「UIController」クラスを継承した「PauseUIController」を作成
  2. 「PauseUI」にアタッチします。
  3. 以下のようにしました。
class PauseUIController
public class PauseUIController : UIController
{
    public override void InitUI()
    {
        GameManager.Instance.PauseUIController=this;
        base.InitUI();
    }

}

スクリプトざっくり解説

  • overrideして自身のインスタンスを「GameManager」に渡す処理を加えました。
  • 初心者的にはoverrideは子クラスで継承元に変更を加えて再定義、子クラスでの定義を優先する感じ。クラスの中でそこだけカスタムパーツやトッピングを変更するみたいなイメージです。

SetActiveの思わぬ失敗

少しハマった部分があったので参考に。Unity プロジェクトでスクリプトが少しだけわかってきたころ初期化を「OnEnable」に書くことも出てくる時があると思います。

ただし今回のようにSetActiveを使うときは注意が必要です「OnEnable」はオブジェクトがアクティブ有効になったときに呼ばれるイベントです。おわかりいただけただろうか。

開かずのUIになってしまうことに。。。

初期化でUIを非表示にする設定で、OpenUI()で開くとOnEnable()の初期化が呼ばれてすぐ非表示になってします。

SetActiveの思わぬ失敗、初期化する場所に注意しよう

  • 初期化でSetActiveを使ってるときは実行する場所に気を付けよう。決して開かずのUIを作らないように

Buttonを実装するスクリプトの準備

次に各ボタン用のスクリプトを用意します。

一時停止(ポーズ)の実装例(その3-1ボタンのスクリプトの準備①)

  1. ゲームの状態を表すボタンの抽象クラス
class GameStateButton
public abstract class GameStateButton : MonoBehaviour
{
    public abstract void OnPress();
}

スクリプトざっくり解説

  • 抽象化クラスはクラスの一部または全部を実装のない抽象化した基底クラスです。継承先で実装を強制できます。

一時停止(ポーズ)の実装例(その3-1ボタンのスクリプトの準備②)

  1. 各ボタンのスクリプトを作成しそれぞれにアタッチします。
class PauseButton
public class PauseButton : GameStateButton
{
    public override void OnPress()
    {
        GameManager.Instance.UpdateCurrentState(GameState.pause);
    }
}
class ResumeButton
public class ResumeButton : GameStateButton 
{
    public override void OnPress()
    {
        GameManager.Instance.UpdateCurrentState(GameState.resume);
    }
}
class RetryButton
public class RetryButton: GameStateButton
{
    public override void OnPress()
    {
        GameManager.Instance.UpdateCurrentState(GameState.retry);
    }
}
class QuitButton
public class QuitButton : GameStateButton
{
    public override void OnPress()
    {

    }
}

スクリプトざっくり解説

  • ボタンを押すとそれに対応したゲームの状態を「GameManager」に知らせます
  • Quitは後々実装するので中身は空のままになっています。

GameManagerに変更を加えます。

対応する処理をGameManagerに追加します。

GameManagerのスクリプトです。

class GameManager
using UnityEngine.SceneManagement;

public class GameManager : Singleton<GameManager> 
{
    //省略
    public PauseUIController PauseUIController {  get; set; } 

    public void UpdateCurrentState(GameState newGameState)
    {
        CurrentGameState = newGameState;
        switch (newGameState)
        {
            //省略

            case GameState.pause:
                Time.timeScale = 0f;
                Pause();
                break;

            case GameState.resume:
                StartCoroutine(Resume());
                Time.timeScale = 0f;
            break;

            case GameState.retry:
                Retry();
                Time.timeScale = 1f;
                break;
                
          //省略

            default:
                throw new ArgumentOutOfRangeException
                    (nameof(newGameState),newGameState, $"UpdateCurrentStateにて予期せぬステート{newGameState}が指定されました");

        }

    }

    //省略

    private void Pause()
    {
        PauseUIController.OpenUI();
    }

    IEnumerator Resume()
    {
        PauseUIController.CloseUI();
        yield return new WaitForSecondsRealtime(0.8f);
        UpdateCurrentState(GameState.active);
    }

    private void Retry()
    {
        SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        UpdateCurrentState(GameState.gamestart);
    }

    //省略

}

スクリプトざっくり解説

  • (6)PauseUIControllerを使うためのプロパティ
  • (15-18,42-45)ポーズの処理
  • (20-23,47-52)再開レジュームの処理。すぐに再開するとプレイヤーが忙しいのでコルーチンを使って動きだしを遅らせています。timescaleを変更して再開後少しスローになっても面白いかもしれませんね。
  • (1,25-28,54-58)リトライの処理
  • (1)SceneManagerのメンバを使うためのnamespace
  • (25-28)リトライの処理 Retry()を実行して、スケール時間を1に戻す
  • (56)GetActiveScene().nameで現在のシーンの名前を取得 LoadSceneで引数のシーンをロードします。
  • (57)ゲームの状態をゲームスタート(gamestart)に変更

画像をボタンにして一時停止(ポーズ)を実装しよう

画像「PauseButton」をボタンにして一時停止(ポーズ)を付けます

一時停止(ポーズ)の実装例(その4一時停止ポーズボタンの実装)

  1. 画像「PauseButton」に「Button」コンポーネントを追加 今回はマウスオーバーとかいらないので「遷移」は「なし」に設定。
  2. 「クリック時()」の「+」をクリックします
  3. 「ない(オブジェクト)」に自身についている「PauseButton」をドラッグしてアサインします。
  4. クリックした際のメソッドを選択できるようになるので「NoFunction」から「PauseButton」スクリプトの「OnPress」を選択します。

メソッドが選択に出てこないとき

  • 今回の機能で使えるメソッドはpublicでvoid(戻り値無し)だけです。
  • あとenum型の引数は使えないようです。使えれば便利なんだけど。拡張すればいいらしいが初心者にはちょっと難しい。

ゲーム再生して、テストしてみましょう。動きましたか?

ボタンがうまく反応しないときは

ボタンの反応がないとき、鈍いときの原因でありがちなのは以下です。

ボタンの反応がないとき

  • 他のオブジェクトが障害になっている。個人的に第1位です。必要なければ他のオブジェクトのRayCastTargetをはずしましょう。外せない場合はシーン上の位置、ヒエラルキーの階層で調整しましょう。
  • 知らないうちに「EventSystem」を削除してしまった。
  • 知らないうちに「Button」コンポーネントの「Interactable」のチェックが外れてる

他にも原因となるものはありますが、とりあえず上記をチェックしてみてください。

復帰レジューム機能の実装

同様に画像「CloseIcon」をボタンにし再開(レジューム)を付けます

一時停止(ポーズ)の実装例(その5復帰レジュームの実装)

  1. 画像「CloseIcon」に「Button」コンポーネントを追加 今回はマウスオーバーとかいらないので「遷移」は「なし」に設定。
  2. 「クリック時()」の「+」をクリックします
  3. 「ない(オブジェクト)」に自身についている「ResumeButton」をドラッグしてアサインします。
  4. クリックした際のメソッドを選択できるようになるので「NoFunction」から「PauseButton」スクリプトの「OnPress」を選択します。

リトライ機能も実装してみよう

リトライボタンも同様に実装します。

最後にゲーム再生して、テストしてみましょう。

開閉のメソッドをボタンから直接行うか迷いましたが、次のゲームオーバーの実装の兼ね合いでGameManagerからおこなってます。

まとめ

まとめ

  • 一時停止ポーズの処理はtimescaleを0にしてストップ
  • 再開レジュームの処理はtimescaleを1(0より大きい数字)にすれば再開
  • 画像に「Button」コンポーネントをつけるとButtonとして使用できる
  • Buttonが反応しないときは、特に他のオブジェクトが障害になっていないかチェックする
  • 「Button」で使えるメッソドはpublicでvoid(戻り値無しのもの)
  • 初期化でSetActiveをあつかうときは実行する場所に注意する(OnEnableだとうまくいかない場合がある)
  • クラスを便利に使う「virtual-override」、「interface」も余裕があったら覚えておこう
ユニティちゃん公式ホームページへ
ユニティちゃん公式ホームページ
ユニティちゃんライセンス
ユニティちゃんの画像、素材、ライセンスロゴはユニティちゃんライセンス条項を元に使用しています

\ Unityのスクリプトを書くのに役立ちます /

もっと早く教えてほしかった!Unity C#入門

MARU

マケイヌ的おすすめ度

わかりやすい度

目指せ脱初心者

〇おすすめポイント

ボリューム大でC#学習にもよく使う関数のチェックにもOK

×よくないポイント

始めたばかりの人にはちょっと難しい

おすすめ記事

 

プロフィール

マケイヌ

人生のメインストリームから外れた40代の♂。

90年代オルタナにはまり、文字通りメインストリームから逸脱。 その後もたびたび人生から逃亡。

心が動いた作品の紹介や 自分のちいさな経験、HowToを発信できればと日々模索中。

1年後までにイラストと写真のポートフォリオをつくりたい。

記:2019年12月

▼プロフィールはこちら

Follow me

アーカイヴ