UI オブジェクトの選択をループさせる

ページ更新日 :
ページ作成日 :

検証環境

Windows
  • Windows 11
Unity エディター
  • 2020.3.25f1

この Tips の前提設定

この Tips の説明の前提として以下の設定を事前に行っています。

参考

サンプルの UI オブジェクトの配置

Canvas にボタンを以下のように配置します。選択しているオブジェクトはわかりやすいように緑色で表示するようにしています。

オブジェクトの選択は選択した方向にあるものしか選択できない

UI オブジェクトを配置したとき、初期状態ではキーボードやゲームパッドで方向キーを押すと指定した方向にある UI オブジェクトを選択できるようになっています。 これは非常に直観的で分かりやすいため設定をわざわざ変える必要はないかと思います。

しかしメニューのようなレイアウトで「一番下を選択した状態で下を押したときに一番上に戻る」というような選択のループ動作は初期設定ではできません。

上の図でいうと Button3 を選択した状態で下を押しても Button1 を選択することはできません。 もちろん Button1 を選択している状態で上を押しても Button3 は選択できません。

選択をループさせる

ここでは選択を延々とループできるような仕組みを作ります。サンプルのレイアウトでいうと Button3 を選択している状態で下を押すと Button1 を選択でき、Button1 を選択している状態で上を押すと Button3 が選択できます。

この制御についてはスクリプトで行います。少ない記述で使用でき他のシーンでもそのまま使える汎用的なスクリプトになっていますが、 その代わり以下の制限がつきます。

  • 上下一方向にしか移動できない
  • 指定したオブジェクト配下に存在するすべての Selectable に適用される

なので利用対象は上下にスクロールして選択するメニューなどに絞られてしまいますが、そのレイアウトに限定するなら非常に有用です。 ちなみに上下限定ですが、スクリプトを少し直せば左右限定にすることもできます。

プロジェクトにスクリプトを作成します。名前はなんでもよいですがここでは SelectLoop としておきます。

スクリプトは以下のようにします。

using UnityEngine;
using UnityEngine.UI;  // 追加

public class SelectLoop : MonoBehaviour
{
  // 最初のフレーム更新の前に開始が呼び出されます
  void Start()
  {
    // ボタンなど選択可能なコンポーネントを取得する
    var selects = GetComponentsInChildren<Selectable>();
    for (var i = 0; i < selects.Length; i++)
    {
      var nav = selects[i].navigation;
      nav.mode = Navigation.Mode.Explicit;
      nav.selectOnUp = selects[i == 0 ? selects.Length - 1 : i - 1];
      nav.selectOnDown = selects[(i + 1) % selects.Length];
      selects[i].navigation = nav;
    }
  }

  // 更新はフレームごとに1回呼び出されます
  void Update() { }
}

やってることはキーの選択動作となる navigation に対して以下の設定を行っています。

  • 上キーを押したときはひとつ前のオブジェクトを選択、1番目のオブジェクトの場合は最後のオブジェクトを選択
  • 下キーを押したときは次のオブジェクトを選択、一番最後のオブジェクトの場合は最初のオブジェクトを選択

ちなみにこのオブジェクト(Selectable)の並びはヒエラルキーの並びに依存していますので、 ヒエラルキーで選択させたい順番に並べておいてください。

スクリプトを保存したらコンポーネントとしてアタッチさせます。 このスクリプトはアタッチしたオブジェクトの中にある Selectable に適用されるので今回は Canvas にアタッチします。

実際に動かし Button1 と Button3 の間をキー操作で移動できるか確認してみてください。