テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】出来るだけ簡単にNew Input Systemを使いたい

新しいInput Systemは少し面倒くさい

 新しいInput Systemですが、正直な意見として面倒くさいというのがあります。アクションにキーを割り振るという思想は非常に理にかなっていますし、応用で色々出来るのは悪くないとは思いますが、以前のInput Managerのようにすぐ使えないのはすごくマイナスです。

 そこで、サクッと使える使い方について確認してみます。

PlayerInputを使用する

 サクッとプレイヤーの入力を取得するアプローチとしてPlayerInputコンポーネントがあります。このコンポーネントを使えば面倒くさい作業が多少楽になります。

  • WASDやGamepadに対応した移動等を含むInputActionsを生成してくれる。
  • SendMessageで該当のメソッドを呼び出してくれる
  • InputSystemの初期化

 特にInputActionsの生成は面倒くさい項目の一つなので、とりあえず動くものがサクッと手に入るのは非常に楽でよいです。ここで生成するInputActionsのアクションマップには「WASDキーやGamePadでの移動」「マウス操作や右スティックの視点移動」「マウスクリックやゲームパッドに反応する射撃」の操作が含まれます。

f:id:tsubaki_t1:20191014213847j:plain
作られたInputActions。とりあえず移動、視点移動、射撃がカバーされる

 なおこの記事はUnity 2019.2 × InputSystem 1.0 の組み合わせで作成されています。

PlayerInputの利用手順

  1. 入力を受け付けたいオブジェクトにPlayerInputコンポーネントを登録。
  2. PlayerInputのCreateActionsを押して、アクションマップを生成。
  3. PlayerInputのDefaultMapPlayerに変更。
  4. PlayerInputのBehaviourをSendMessage`に変更

 

f:id:tsubaki_t1:20191014210641j:plain
PlayerInputからActionMapを作るボタン

 あとは下のコードを記述してPlayerInputをアタッチしたGameObjectに追加します。入力はそのまま使用せず、いったんフィールドにキャッシュして使用します。これは現状InputSystemが変化した値を検出するためです。

 なおSendMessageと聞いて顔をしかめるかもしれませんが、今の端末性能的に一フレーム数回のSendMessageなど誤差のようなものです。

using UnityEngine;
using UnityEngine.InputSystem;

public class Example: MonoBehaviour
{
    public Vector2 move { get; private set; }
    public Vector2 look { get; private set; }
    public bool fire { get; private set; }

    public void OnMove(InputValue value) => move = value.Get<Vector2>();
    public void OnLook(InputValue value) => look = value.Get<Vector2>();
    public void OnFire(InputValue value) => fire = value.Get<float>() > 0;

    void Update()
    {
        Debug.Log($"Move[{move}], Look[{look}], Fire[{fire}]");
    }
}

 もしポーリングするスタイルで使用したい場合、下のような記述になります。playerInput.actions["アクション名"]でアクションの情報が取得できるので、あとはReadValueで現在の状態を取得していく感じです。

using UnityEngine;
using UnityEngine.InputSystem;

public class Example: MonoBehaviour
{
    InputAction move, look, fire;
    void Start()
    {
        var playerInput = GetComponent<PlayerInput>();
        move = playerInput.actions["Move"];
        look = playerInput.actions["Look"];
        fire = playerInput.actions["Fire"];
    }

    void Update()
    {
        var m = move.ReadValue<Vector2>();
        var l = look.ReadValue<Vector2>();
        var f = fire.ReadValue<float>() > 0;

        Debug.Log($"Move {m}, Look {l}, Fire {f}");
    }
}

 なおPlayerInputにはUnityEventを受け取るという機能もありますが、これはUnity 2019.3では動作しませんでした。同梱のサンプルも動作しないのでバグと思われます(2019.2では動作します)。Unity 2019.3 b7だと正常に動作しました

キー入力やゲームパッドの取得

 デバッグ目的等でサクッと特定のキー入力を使用したい場合、下のような形で取得出来ます。InputActionのように入力をアクション単位で抽象化出来ないので、サクッと使える反面、複数の環境に対応させようと思ったら少し面倒くさいことになるかもしれません。

// マウスの左クリックを検出
Mouse.current.leftButton.wasPressedThisFrame;
// キーボードのスペースキーを検出
Keyboard.current.spaceKey.wasPressedThisFrame;
// ゲームパッドの左スティックを検出
Gamepad.current.leftStick.ReadValue();

関連

tsubakit1.hateblo.jp