見出し画像

【Unity】キーボード入力時にボタンを自動で選択する

ボタンの問題点

Buttonコンポーネントは、マウスとキーボード(コントローラ)で挙動が異なります。

マウス
カーソルをボタンに合わせるとボタンがHighlighted状態になり、クリックするとPressed状態になり、その後はSelected状態になる。

キーボード・コントローラ
デフォルトでは何もできない。Selected状態のボタンがある場合、方向キーを押すと隣のボタンがSelected状態になる。

一度マウスでボタンを押さないと方向キーが反応しないのは不便すぎる・・・
そしてキーボード操作からマウス操作に変えた時にSelected状態のボタンが光ったままなのはダサい・・・

解決策

入力デバイスに応じてSelected状態を自動変更するコンポーネントを作りました。Canvasオブジェクトに付けるだけで動きます。

AutoSelectionForButtonDevice.cs
※InputSystemを使います。
※コピペして使う場合は #if INPUT_SYSTEM#endif を削除してください。

機能:
キーボード等の入力があった場合は先頭のボタンを検索してSelectedにします。
マウス入力に切り替わった場合はSelectedを解除します。

コード解説

最後に使用した入力デバイスを取得

InputSystem.onEvent
    .Where(e => e.type == StateEvent.Type || e.type == DeltaStateEvent.Type)
    .Call(e =>
    {
        var control = e.EnumerateChangedControls().FirstOrDefault();
        _detectedControl = control?.device is Pointer ? Control.Pointer : Control.Button;
    });
  • Where()の中身はおまじないのようなもので、EnumerateChangedControls()の実行に必要な絞り込みです。

  • EnumerateChangedControls().FirstOrDefault()で入力値の変化情報を1つ取り出します。

    • GetAllButtonPresses()でも良さそうですが、コントローラのスティック入力にも反応させたかったので採用しませんでした。

  • 入力デバイスの型をチェックします。今回はPointerかどうかを調べます。

Selected状態にするボタンを検索

private static readonly List<Selectable> SelectableBuffer = new List<Selectable>();
public Selectable Find(GameObject root)
{
    root.GetComponentsInChildren(SelectableBuffer);
    var count = SelectableBuffer.Count;
    for (var i = 0; i < count; i++)
    {
        var selectable = SelectableBuffer[i];
        if (selectable.IsInteractable())
        {
            return selectable;
        }
    }
    return null;
}
  • ボタンと言いつつSelectableを検索しています。これでButton以外のSelectableを継承しているUIも検索対象になります。

  • 子のリストから操作可能なボタンを探します。

  • この処理自体は外部から差し替え可能にしています。

ボタンのSelected状態を変更

// 選択
selectable.Select();

// 選択解除
EventSystem.current.SetSelectedGameObject(null);

宣伝

アセットストアで便利ツールを販売しています!

お布施も受け付けています!


この記事が気に入ったらサポートをしてみませんか?