[Unity] シンプルにボタンを作ってみる 続き

Nプログラマです。

前回の記事:シンプルにボタンを作ってみるで、シンプルなボタンを作りました。
そして、以下のような課題が残りました。

ボタン専用メソッドを一つにまとめる。

今回の記事では、この課題に対応した内容を記載していきます。

概要

今回は道具のメニュー画面を作る、という想定のもと、どのボタンが押されたかという部分を作ります。

GUIを含めた見た目がおしゃれなメニュー画面を作るわけではないので、ご注意を。

さて、道具のメニューには以下のボタンがあるとします。

  • 次のページへ進む
  • 閉じる
  • アイテムを使う

画像だとこんな感じ。

/img/article/2019/03/02/01.png
作成するボタンのイメージ

これら3つのボタンでどれが押されたのかを判別する必要があります。

前回の内容はこんなヒエラルキーの構造になっていました。

/img/article/2019/03/02/02.png
前回のボタンの階層構造

今回は、MenuとButtonの間にMenuItemを挟むことにしますのでこんな感じになります。

  • Menu
    • MenuItem
      • Button

MenuItemはメニューの項目という意味で使います。
(ゲームでは道具というイメージが強いですよね)

作りは結構シンプルで、どちらかというとインスペクタでの作業が多くなりそうです。

実装

ソースコード

SampleInit.cs (Editor)

SampleInit.cs コードを開く
SampleInit.cs
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;

public class SampleInit 
{
    [UnityEditor.MenuItem("Tool/InitScene")]
    public static void InitScene()
    {
        var goCanvas = GameObject.Find("Canvas");
        GameObject.DestroyImmediate(goCanvas);

        EditorApplication.ExecuteMenuItem("GameObject/UI/Button");
        var templateButton = GameObject.Find("Button"); // ExecuteMenuItemで作成されたボタン
        goCanvas = GameObject.Find("Canvas");
        // メニューゲームオブジェクトを作成
        var goMenu = new GameObject("Menu");
        goMenu.transform.SetParent(goCanvas.transform);
        goMenu.transform.localPosition = Vector3.zero;
        goMenu.AddComponent<Menu>();
        
        string[] buttonNames = {
            "MenuItemClose",    // 閉じるボタン
            "MenuItemNext" ,    // 次へボタン
            "MenuItemUse",      // 使うボタン
        };
        Vector2[] buttonPositions = {
            new Vector2(-200, 0),
            new Vector2(   0, 0),
            new Vector2( 200, 0),
        };
        for (int i = 0; i < buttonPositions.Length; i++)
        {
            // MenuItem
            var goMenuItem = new GameObject(buttonNames[i]);
            var menuItem = goMenuItem.AddComponent<MenuItem>();
            menuItem.buttonName = buttonNames[i];
            goMenuItem.transform.SetParent(goMenu.transform);
            goMenuItem.transform.localPosition = Vector2.zero;

            // ボタン
            var goButton = GameObject.Instantiate(templateButton, Vector3.zero, Quaternion.identity);
            var button = goButton.GetComponent<Button>();
            button.transform.SetParent(goMenuItem.transform);
            button.transform.localPosition = buttonPositions[i];
            button.name = buttonNames[i] + "Button";
            var textComp = button.GetComponentInChildren<Text>();
            textComp.text = buttonNames[i];
        }
        
        GameObject.DestroyImmediate(templateButton); // コピー用オブジェクトを削除
    }
}

説明

いつもの初期化用スクリプトです。

シーンファイルの中身を書き換えるので、新規のサンプル用プロジェクトでの実行をお願いします。

やっていることは前回同様、概要にあるヒエラルキーの図のゲームオブジェクトを作成して配置しています。

配置後は、インスペクタでButtonのOnClickの項目を設定すれば準備完了です。

MenuItem.cs コードを開く
MenuItem.cs
using UnityEngine;

public class MenuItem : MonoBehaviour
{
    public string buttonName;
}
view rawMenuItem.cs hosted with  by GitHub

説明

どのボタンがおされたかを判別したいので、MenuItemに名前を持たせることにします。

インスペクタから以下の名前のいずれかを入力します。 この名前を使って、Menuの中で名前からどのボタンが押されたかを判定します。

  • MenuItemClose
  • MenuItemNext
  • MenuItemUse
Menu.cs コードを開く
Menu.cs
using UnityEngine;

public class Menu : MonoBehaviour
{
    public void OnClick(MenuItem menuItem)
    {
        switch (menuItem.buttonName)
        {
            case "MenuItemClose":   // 閉じる
                Debug.Log("clicked close.");
                break;
            case "MenuItemNext":    // 次のページ
                Debug.Log("clicked next.");
                break;
            case "MenuItemUse":     // アイテムの使用
                Debug.Log("clicked item use.");
                break;
        }
    }
}

説明

前回は、OnClickXXXという風に、各ボタン毎の専用メソッドを作成していました。

今回は、ボタン専用メソッドがOnClickメソッド一つになってスッキリしたと思います。

switchの内部では、各ボタンについている名前からどのボタンを押したのかを判定して、メッセージを表示しています。

これでボタンが押された処理を集約することができました。

あとは、インスペクタでOnClickにポチポチ設定していけばいいですね。

/img/article/2019/03/02/03.png
ボタンの設定

実行結果

起動したら3つのボタンが表示されますので、それぞれのボタンを押してConsoleに押されたボタンに対する出力が表示されたらオッケーです。

表示されない時は、ButtonのOnClickの設定が未設定の可能性があるので確認してみてください。

考察

今回の内容で、以下の課題が見えてきました。

  1. ボタン種類の判定が、文字列の比較
  2. OnClickの引数がMenuItem

1. ボタン種類の判定が、文字列の比較

MenuItemボタン判別用の名前を入力するという設計して作ってみたものの、

Inspectorでの入力と、実装のswitchの部分の二箇所を入力しないといけないので、手間がかかるのとタイプミスが心配なところです。

これは文字列の代わりに、列挙体を使えば解決しそうです。

2. OnClickの引数がMenuItem

ここは作り方によって変わるかと思います。

MenuItemしか使わないというならこのままでもいいですが、switch内部で押されたボタンに応じて使うコンポーネントを切り替えたい時があるかもしれません。

そういう時は、引数をGameObjectにしておくといいかもいいかもしれません。

GameObjectならGetComponentで任意のコンポーネントを取得することができます。

こうしておけば、Menuの方で実装の自由度が上がりそうです。

まとめ

今回は、ボタンを押した時のメソッドを一つにまとめるという内容でした。 次回は、考察で書いた課題を改善してもう少し使いやすくしてみます。

それでは、このへんで。
バイナリー!



関連した記事