【Unity】Actionの指定を便利にするInputActionPropertyの使い方

こじゃらこじゃら

インスペクターからInput SystemのActionを指定する時、直接指定なのかInput Action Assetの参照なのかを場面に応じて変える方法はないの?

このはこのは

InputActionProperty構造体を使えば良いわ。

Input SystemのActionをスクリプトから扱う際、インスペクターからActionを指定する方法は主に次の2通りが考えられます。

  • Input Actionの設定内容を直接指定する
  • Input Action Asset側で管理しているAction(参照)を指定する

両者はそれぞれデータの持ち方が別ですが、InputActionProperty構造体を使うと、同じスクリプトで動的にどちらの方法でActionを設定するかを切り替えることができます。

参考:Struct InputActionProperty | Input System | 1.5.1

InputActionProperty型として[SerializeField]などでフィールド定義すると、以下のようにインスペクターから指定方法を切り替えてActionを設定できるようになります。

本記事では、このInputActionPropertyの使い方について解説していきます。

動作環境
  • Unity 2022.2.16f1
  • Input System 1.5.1

スポンサーリンク

前提条件

事前にInput Systemパッケージがインストールされ、有効化されているものとします。

ここまでの手順は以下記事で解説しています。

また、Input Action経由で入力を受け取ることとします。

Input Actionの基本的な使い方は以下記事で解説しています。

InputActionProperty構造体の使い方

次のようにフィールド定義するだけで使えます。

// InputActionProperty構造体のフィールドを定義
// これでインスペクターからの設定が可能になる
[SerializeField] private InputActionProperty _actionProperty;

以下、InputActionProperty構造体をフィールドで定義し、ここからInputAction経由で入力を取得するサンプルです。

InputActionPropertyExample.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class InputActionPropertyExample : MonoBehaviour
{
    // InputActionProperty構造体のフィールドを定義
    // これでインスペクターからの設定が可能になる
    [SerializeField] private InputActionProperty _actionProperty;

    private void Awake()
    {
        // InputActionインスタンスを取得
        var action = _actionProperty.action;

        // Actionが無かったら何もしない
        if (action == null) return;

        // performedコールバックにOnPerformedメソッドを登録
        action.performed += OnPerformed;
        
        // Actionを有効化して入力を受け取れるようにする
        action.Enable();
    }

    // インスペクターで設定されたActionのperformedイベントが発火したら呼ばれる
    private void OnPerformed(InputAction.CallbackContext context)
    {
        // InputActionの名前をログ出力
        Debug.Log($"OnPerformed: {context.action.name}");
    }
}

上記をInputActionPropertyExample.csという名前で保存し、適当なゲームオブジェクトにアタッチします。

すると、以下のようにインスペクターからActionを設定できるようになるため、お好みのActionを設定してください。

上記のようにUse Reference項目チェックを外すと、Actionを直接スクリプト側で定義できるようになります。

Use Referenceにチェックを入れると参照モードとなり、Input Action AssetのActionのアタッチ(参照の指定)が可能になります。

例では、直接Actionを定義し、スペースキーが押されたらperformedコールバックが発火するBindingを定義してみます。

実行結果

指定されたActionのキーが押されるたびに、コンソールにログ出力されます。

参照モードで実行すると、次のようにInput Action Assetで定義したAction名がログ出力されます。

スクリプトの説明

まず、[SerializeField]属性などでInputActionProperty型をシリアライズ可能なフィールドとして定義します。

// InputActionProperty構造体のフィールドを定義
// これでインスペクターからの設定が可能になる
[SerializeField] private InputActionProperty _actionProperty;

その後、上記のインスペクターから設定されたActionをInputActionインスタンスとして取得します。actionプロパティから取得できます。

// InputActionインスタンスを取得
var action = _actionProperty.action;

// Actionが無かったら何もしない
if (action == null) return;

未定義の場合もあり得るため、nullチェックも行っています。

InputActionインスタンスを無事に取得できたら、performedコールバックにメソッドを登録し、Actionを有効化します。

// performedコールバックにOnPerformedメソッドを登録
action.performed += OnPerformed;

// Actionを有効化して入力を受け取れるようにする
action.Enable();

注意

Actionの有効化を忘れると、performedコールバックに登録しても入力を受け取れない(コールバックが発火しない)のでご注意ください。

InputActionProperty構造体の仕様

InputActionProperty構造体の仕様は以下リファレンスに記載されています。

参考:Struct InputActionProperty | Input System | 1.5.1

基本的に、スクリプト中から扱うのは次のactionプロパティでしょう。

public readonly InputAction action { get; }

直接指定か参照指定かによって返すActionを内部的に振り分けてくれるため、使用側が特に意識する必要はありません。

また、referenceプロパティによってActionへの参照(InputActionReference型)を取得することも可能です。

public readonly InputActionReference reference { get; }

ただし、参照モード(インスペクターからUse Referenceにチェックが入っている状態)でないと常にnullを返します。

InputActionProperty構造体の内部実装

内部的には次の3つのシリアライズ可能フィールドを持っています。 [1]

// 参照を使用するかどうか
[SerializeField] private bool m_UseReference;

// 直接指定時のInputAction設定情報
[SerializeField] private InputAction m_Action;

// 参照指定時のActionへの参照情報
[SerializeField] private InputActionReference m_Reference;

直接指定か参照指定かを示すフラグm_UseReferenceを持ち、それぞれの指定に応じた設定情報を両方保持しています。

直接指定の時はm_Actionフィールド、参照指定の時はm_Referenceフィールドが内部的に使用されます。

インスペクター上では、エディタ拡張(Property Drawer)によってm_UseReferenceフィールドの状態に応じて必要なフィールド(m_Actionかm_Referenceか)のみを設定可能になるように表示切り替えしています。

さいごに

InputActionPropertyをAction指定用のフィールドとして用いると、臨機応変にActionの指定方法を変えることができます。

スクリプトから単独のActionを指定する場合に活躍できるでしょう。

ただし、余分にフィールドを持つことになり、シリアライズされるデータサイズが増えることを念頭に置けば良いでしょう。

関連記事

参考サイト

スポンサーリンク