[unity2019]新 Input System をさらに簡単に使いたい

こちらの記事は内容が古くなっています。最新の記事をご覧ください。

前回の記事で新 Input System の簡単な使い方を紹介しましたが、本気でパッドやキーボード入力をコントロールするには色々とタリナイ機能があるものです。

欲しい機能

旧 Input を簡単に置き換えたい!

まずはこれですね! 確かに置き換えは可能ですが、新 Input System では Keyboard.current が null になる可能性もあるので、そのチェックも必要です。

if (Input.GetKeyDown(KeyCode.LeftArrow) == true)
{
}

↓

if (Keyboard.current != null)
{
    if (Keyboard.current[Key.LeftArrow].wasPressedThisFrame == true) {}
}

この置き換えは中々骨が折れますね…。

PadInput では次のように置き換えます。Input とほぼ同じ。
内部で新 Input System の null チェックもしているので、意識する必要はありません。

if (Input.GetKeyDown(KeyCode.LeftArrow) == true) {}

↓

if (Padd.GetKeyDown(ePad.LeftArrow) == true) {}

パッドとキーボードを一つのコードで判定したい

新 Input System で、例えば「決定ボタン」の判定はこんな感じでしょうか。

// スペースキー、PS4で〇が決定キーとする
if (GamePad.current.buttonEast.wasPressedThisFrame == true || Keyboard.current[Key.Space].wasPressedThisFrame)
{
    // キーが押された処理
}

このコードをあらゆる箇所に書くのは非常に面倒です。
「やっぱり決定はスペースじゃなくてエンター💛」とか仕様変更されればおそらく何十か所の修正を誤りなく行うことになりますし、第一上のコードではパッドを繋いでない場合、エラーになってしまいます。

こんな感じで呼び出しは一つだけ、面倒な事はライブラリ内で解決して欲しいですね。

if (Padd.GetKeyDown(ePad.MenuOK) == true)
{
    // キーが押された処理
}

キーディレイを考えた入力情報が欲しい

タップ操作では不要ですが、パッドやキーボード操作でメニューを移動させる場合、カーソル移動は「適切な間」を取って動く必要があります。

間がないと、このように早すぎて項目を選べなくなります。
一瞬で 200 くらい移動しているのがわかるでしょうか。

速すぎて選択できない

この「適切な間」を取ったキー値をデフォルトでは取得することはできません。
出来ればこう書くだけでいい感じに動いて欲しいです。

// ディレイつきキー入力
if (Padd.GetKeyDelay(ePad.UpArrow) == true)
{
    // キーが押された処理
}
期待の動作

キーコンフィグが欲しい

昨今はキーコンフィグがあるだけでゲーム評価の上がる傾向があり、ローカライズで特定のボタンを入れ替えるなんてこともあるでしょう。
PadInput では簡単なキーコンフィグ機能もついています(説明は後述)。

ダウンロード

使い方

Padd クラスを適当な GameObject につければ利用が可能になります。
Input.GetKeyDown(KeyCode.UpArrow) -> Padd.GetKeyDown(ePad.UpArrow) のように、旧Input に慣れている人が違和感なく使えるよう設計されています。

ePad

KeyCode の代わりに使います。
PadInput という名の通り、パッドに割り当てられるキーのみです。

あまりないとは思いますが… PC Only、キーボードをフルで使うようなアプリは、向いていません。

また、同じボタンに複数の名前が割り当てられています。KeyCode っぽい名前や、各種コントローラに対応した名前です。
使いやすい名前を使ってください。いくつか例を挙げておきます。

上キー

ePad.VecUp
ePad.UpArrow

×キー

ePad.ButDown
ePad.Cross
ePad.AButton

マウスのボタン

ePad.MouseLeft

どれかキーが押された

ePad.AnyKey

AnyKey は新 Input System で非推奨となっている all を使っているわけではなく、ローコストで実現しています。

Padd.GetKey(ePad key)

ボタンを押している間 true が返されます。Input.GetKey() の代わり。
マウスボタンの状態も取得することができます。

Padd.GetKey(ulong buttonBit) は下のような状況で使うと少しだけ便利かも…?

if (Padd.GetKey(ePad.L1) == true || Padd.GetKey(ePad.R1) == true)
{
    // L1R1 どちらかが押されたら
}

if (Padd.GetKey(PadInput.B_L1 | PadInput.B_R1) == true)
{
    // L1R1 どちらかが押されたら
}

Padd.GetKeyDown(ePad key)

ボタンを押した瞬間 true が返されます。Input.GetKeyDown() の代わり。
マウスボタンの状態も取得することができます。

Padd.GetKeyUp(ePad key)

ボタンを離した瞬間 true が返されます。Input.GetKeyUp() の代わり。
マウスボタンの状態も取得することができます。

Padd.GetKeyDelay(ePad key)

キーディレイつきボタン入力が返ります。押しっぱなしにするとトン……..トン、トン、トンと自動的に間を置いて返す感じです。
メニューの上下左右移動などに重宝するメソッドです。(KeyDown でも出来なくはないが、ユーザビリティは悪くなる)
マウスボタンの状態も取得することができます。

上下の「間のある」移動は GetKeyDelay() で実現している

Padd.GetAxisL()
Padd.GetAxisR()

パッド左スティック、右スティックのアナログ値を返します。
今のところキーボードに割り当ててはいませんが、PadInput.getRawControl_Keyboard() を拡張すれば、割り当てることも可能です。

Padd.GetTrigger()

パッドL2、R2の押し込みアナログ値を返します。
今のところキーボードに割り当ててはいませんが、PadInput.getRawControl_Keyboard() を拡張すれば、割り当てることも可能です。

Padd.MouseWheel()

マウスホイールの移動量を取得することができます。

Padd.DebugKey(UnityEngine.InputSystem.Key key)
Padd.DebugKeyDown(UnityEngine.InputSystem.Key key)

デバッグ用。ほぼ旧 Input と同じことができますが、エディタでのみ使用可能なデバッグ機能なので、実際のゲーム入力には使用しないでください。

押されたキーを確認したい

視認可能な TextMeshPro オブジェクトを適当に1つ作成し、Padd Debug Text に登録します。

このように、押されたキーが全て表示されます。
(1つのキーが、複数に割り当てられているのは正常です。例えば AnyKey は何を押しても反応します)

この機能はエディタでのみ動作し、ビルドには含まれません。

キーコンフィグ

PadIInput で以下のように定義されています。1つのボタンにつき、複数のキー(キーボード)を定義することができます。
また、パッドのボタン入れ替えも可能です。

        public KeyConfig()
        {
            FirstDelay  = 0.25f;
            SecondDelay = 0.04f;

            VecU   = new Key[] { Key.UpArrow, Key.Numpad8, Key.W };
            VecD   = new Key[] { Key.DownArrow, Key.Numpad2, Key.S };
            VecL   = new Key[] { Key.LeftArrow, Key.Numpad4, Key.A };
            VecR   = new Key[] { Key.RightArrow, Key.Numpad6, Key.D };
            ButD   = new Key[] { Key.Z, Key.Enter, Key.NumpadEnter };
            ButR   = new Key[] { Key.X, Key.Escape, Key.Backspace };
            ButL   = new Key[] { Key.C, Key.NumpadDivide };
            ButU   = new Key[] { Key.V, Key.NumpadMultiply };
            L1     = new Key[] { Key.Q, Key.Numpad7, Key.LeftShift };
            R1     = new Key[] { Key.E, Key.Numpad9, Key.LeftCtrl };
            L2     = new Key[] { Key.RightShift };
            R2     = new Key[] { Key.RightCtrl };
            L3     = new Key[] { };
            R3     = new Key[] { };
            Select = new Key[] { Key.F1, Key.Numpad1 };
            Start  = new Key[] { Key.F2, Key.Numpad3 };
            Touch  = new Key[] { };

            Pad    = new ePad[(int)ePad.PadMax];
            for (int i = 0; i < Pad.Length; i++)
            {
                ePad epad = (ePad)Enum.ToObject(typeof(ePad), i);
                Pad[i] = epad;
            }
        }
FirstDelay
SecondDelay
GetKeyDelay() のディレイタイム(秒)
VecU ~ Touchそれぞれのボタンにどのキー(キーボード)を対応させるか
複数指定可能
Padパッドのボタン入れ替えに使う

例えば〇ボタン、×ボタンを入れ替え、スペースキーをL3とする場合は次のようにします。

using UnityEngine.InputSystem;

PadInput.PadConfig config = Padd.GetConfig();
config.Pad[(int)ePad.Cross]  = ePad.Circle; // 右ボタンを押すと下ボタンが反応
config.Pad[(int)ePad.Circle] = ePad.Cross; // 下ボタンを押すと右ボタンが反応
config.L3                    = new Key[] { Key.Space }; // スペースを押すと L3 が反応
Padd.SetConfig(config);

MENU_XXX

ePad.MenuLeft のようなメニューに特化した上下左右、OKキャンセルボタンの取得が可能になっています。これらはデフォルトでは次のように設定されています。

ePad.MenuUp十字キー上、もしくは左スティックで上
ePad.MenuRight十字キー右、もしくは左スティックで右
ePad.MenuLeft十字キー左、もしくは左スティックで左
ePad.MenuDown十字キー下、もしくは左スティックで下
ePad.MenuOKPS4 で×ボタン
ePad.MenuCancelPS4 で〇ボタン

OK、CANCEL は海外仕様となっています。(PS5 では日本でもそうなりましたし、時代の流れかな、と…)
変更したければ、getReserveControl() を書き換えてください。

あとがき

bool の変数を 100個近く作るのが嫌で、ビット演算を使っています。
利点は結構ありましたが、今風ではありません。

ePad.Touch など、用意はしたものの割り当てされてないものもあります。
(PS4にしかありませんしね…)

アナログ値は 0~1 とされていますが、操作していないのに 0.1 だったり、限界まで操作しても 0.8 くらいまでしかいかないコントローラもあったりします。
こういうコントローラでも(疑似的に)0~1 にする方法を追加するのもいいかもしれません。

全ての環境で正常動作させる、というのはなかなか難しいです。色々と調整してみてください。

去年末に買ったアケアカ グラディウス3 のメニューがタッチボタン。マイジョイスティックにはついておらず、悲しみ。

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA