InputSystemでボタンが押され続けていることを検知したい ( IsPressedをつかえ

個人制作でInputSystemを使ってみようと思い試行錯誤

従来のInputから InputSystemへ乗り換えを考えていたとき、 「あるキーが押され続けているか」 という条件をどう取ろうか迷った。

if (Input.GetKey(KeyCode.LeftArrow))
{
    moveDir = Vector2Int.left;
}

従来であれば Input.GetKey でtrueが返ってくるコードだが InputSystem では....


ちなみに、動きだけを表すInputControlsを作成して試している。

キーボードの左キーを押したときはもちろんの事、ActionはButtonにしてUI上の移動ボタンが押されたときにも反応できるようにしてます。

f:id:toshizabeth:20210403191042p:plain


とりあえずリファレンスを確認 (折角?なので現時点で最新のv1.1.0-preview.3で実行しています) Polling Actionsという場所。

Actions | Input System | 1.1.0-preview.3

以下の2つ例で書かれている

    public InputAction moveAction;
    public float moveSpeed = 10.0f;
    public Vector2 position;

    void Start()
    {
        moveAction.Enable();
    }

    void Update()
    {
        var moveDirection = moveAction.ReadValue<Vector2>();
        position += moveDirection * moveSpeed * Time.deltaTime;
    }
    private InputAction action;

    void Start()
    {
        // Set up an action that triggers when the A button is
        // held for 1 second.
        action = new InputAction(
            type: InputActionType.Button,
            binding: "<Gamepad>/buttonSouth",
            interactions: "hold(duration=1)");

        action.Enable();
    }

    void Update()
    {
        if (action.WasPerformedThisFrame())
            Debug.Log("A button on gamepad was held for one second");
    }


まず、 ReadValue<T> 方式ですが、 これで取得できました (目標達成


コードは以下

f (move.Left.ReadValue<float>() > 0f)
{
...
}

このReadValueでは、押され続けている間 1f が返ってきます。


float というのが非常に引っかかる!

(ちなみに ReadValue では変換できないので InvalidOperationException が出ます。)

なぜ float だと ReadValue で取得できるかというと Unity のInpusSystemのGithubからButtonWithOneModifierを参照すると float の InputBindinfComposite を継承しているから

InputSystem/ButtonWithOneModifier.cs at df871319560eca94b9d80cec38b55a6d15ac2735 · Unity-Technologies/InputSystem · GitHub


一応これで目的は達成できそうですが他にもみていきます。



次のサンプルのWasPerformedThisFrame はその名の通り 「このフレームで押されたか」 という、押されたとき一回だけのイベントが取れそう

つまり今回の「押され続けているか」とは違う

リファレンスの少し下を見ると InputActon.IsPressed() というメソッドを見つけた。

リポジトリ上でみてもこれ使えそう

InputSystem/InputAction.cs at df871319560eca94b9d80cec38b55a6d15ac2735 · Unity-Technologies/InputSystem · GitHub

(InputSystem周りコメントがぎっしり!サンプルも付いてるし。正直ありがたい)


ということで、リファレンス通り InputControl に対して単純に IsPressed メソッドを使用すれば「押されているか」というイベントがとれました。

if (move.Left.IsPressed())
{
    // 左キーor左ボタンが押されている
}

v1.1 以前はこの IsPressed メソッドはなかった気がする。

以前調べたとき、クラス内では存在していたが公開されていないので悩んだ記憶があります。

ReadValue で「値が0より上か」でとるよりかは直感的で使いやすいですね