Unity - Input Systemを使ってゲームパッドからuGUIを操作する

UnityでInpu System + ゲームパッド + uGUIという構成にしたくて調べたが、情報が少ない感じだったので書く。
UnityのGUIは今後UI Toolkitというものに移っていくらしいが、2021/12の時点ではまだPreviewなのでuGUIを使う。

環境

できあがりイメージ

メニュー画面の呼び出し、カーソルの移動、決定、閉じるをゲームパッドで操作する

やり方

メニュー画面のオブジェクトを作る

特別なことはなし。
今回はPanelButtonを置いて、Button選択時の色を緑にしただけ。

メニュー画面

ActionMapsにボタン割り当てを追加する

プレイヤーキャラクターの移動入力などで使用している.inputactionsに、メニューの開閉と選択項目決定のためのボタン割り当てを追加する。

Player側

メニュー画面の呼び出しはプレイヤーキャラクター操作時に反応してほしいのでPlayer側に追加する。
今回は以下のように割り当てた。

アクション ActionMapsでの名称 ボタン割り当て
メニュー画面を開く Menu Button North(Yボタン/△ボタン)
メニュー画面を閉じる Cancel Button South(Aボタン/×ボタン)

「メニュー画面を閉じる」はUI側に移した。 ActionMapの切り替えを考えると、UI側にまとまっていた方がよさそう。

Player側のボタン割り当て

UI側

Buttonコンポーネントを押す操作はSubmitになるようだ。

アクション ActionMapsでの名称 ボタン割り当て
メニュー項目の決定 Submit Button East(Bボタン/〇ボタン)
メニュー画面を閉じる Cancel Button South(Aボタン/×ボタン)

UI側のボタン割り当て

プレイヤー操作用スクリプトにメニュー画面の開閉イベント処理を書く

書く。

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField] private GameObject _menuUi;
    private ExampleInputSysWithUGUIinputactions _input;

    private void Start()
    {
        SetupInputSystem();
    }

    private void SetupInputSystem()
    {
        _input = new ExampleInputSysWithUGUIinputactions();
        _input.Enable();

        var player = _input.Player;

        // 移動とか回転とかジャンプとか
        // player.Move.performed += (ctx) => _inputtedMove2d = ctx.ReadValue<Vector2>();
        //  …


        // メニュー画面の開閉
        player.Menu.performed += (_) =>
        {
            if (_menuUi && _menuUi.activeSelf) return;

            Time.timeScale = 0;
            _menuUi.SetActive(true);
            Debug.Log("メニューを開く");
        };

        _input.UI.Cancel.performed += (_) =>
        {
            if (!_menuUi || !_menuUi.activeSelf) return;

            _menuUi.SetActive(false);
            Time.timeScale = 1f;
            Debug.Log("メニューを閉じる");
        };

    }

}

メニュー画面用スクリプトにメニュー項目操作イベント処理を書く

マウスでUI操作する時と同様にonClick.AddListenerが使える。
今回はメニュー項目(Button)を押すとログが出るようにした。

なお、カーソルの移動はButtonコンポーネントNavigationがいい感じにやってくれるので書かなくてよいが、カーソルの初期位置はセットしておく必要がある。

using UnityEngine;
using UnityEngine.UI;

public class MenuController : MonoBehaviour
{
    [SerializeField] private Button _itemButton;
    [SerializeField] private Button _equipmentButton;
    // 他のButtonは省略

    private void Start()
    {
        SetupMenuUiEvents();
    }

    // 今回はメニュー画面の表示/非表示をSetActiveで切り替えるので、
    // カーソルの初期位置指定はOnEnableに書く(Startでなく)。
    private void OnEnable()
    {
        // いずれかのButtonを選択状態にしておかないとGamepadでカーソルを移動できない。
        _itemButton.Select();
    }

    private void SetupMenuUiEvents()
    {
        _itemButton.onClick.AddListener(() =>
        {
            Debug.Log("アイテムボタンが押された");
        });

        _equipmentButton.onClick.AddListener(() =>
        {
            Debug.Log("装備ボタンが押された");
        });

        // 閉じるアクションは開くアクションとまとめておきたいのでPlayer側に書いた。
    }

}

オブジェクト類とスクリプトを関連付ける

くっつけたらできあがり。

くっつける

できあがりイメージで使用したアセット