Unityの新しいInputSystemをReactivePropertyに変換し使用する

#はじめに
新しいInputSystemへの移行をReactivePropertyを用いて行います
新しいInputSystemそのままだと使いにくすぎる…

#環境
Unity2020.2

#従来のUnityEngine.Inputからの移行
InputAction自体がInputすべての汎用クラスなので
旧InputのInput.GetButton/Input.GetAxisと同様に使えるよう
3パターンに分けてReactivePropertyへ変換を行います。

* Button 旧:Input.GetButton(Down/Up)
* Delta 旧:Input.GetAxis(MouseX) 例マウスの移動量
* Axis 旧:Input.GetAxis 例Joystick,Horizontal

変換には今回作成した[拡張メソッド](#inputactionをreactivepropertyに変換する拡張メソッド)を使用しています。

##InputActionの設定
* Button

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308905/6f8a261c-cae4-7f1f-3a9a-9f50a27ca02a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308905/5ec88a43-4292-3fe9-80ce-24e3d90d43b4.png)
こちらはデフォルトで大丈夫ですがButtonにしておくとBindingがボタンのみ表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308905/eab7c3d8-a6af-72f4-aa6c-db858c2e5e55.png)
Bindingには押したいボタンを
TriggerBehabiorにはPressAndReleaseを設定します

* Delta

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308905/f335cc68-cd4e-37f3-c3e5-0993e2a553e6.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308905/5ec88a43-4292-3fe9-80ce-24e3d90d43b4.png)
こちらはデフォルトで大丈夫ですがAxisにしておくとBindingがAxisのみ表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308905/308b9a70-f12c-b7d1-28ec-c378a585ff5c.png)

* Axis

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308905/0570d237-1411-3b8d-54a9-e618a173d7b2.png)
ジョイスティックの場合はドリフトするのでDeadZoneを設定すると良いです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308905/808264ff-8895-d7ef-0e1d-07e11b003f5b.png)
キーボードからAxisを作成する場合1DAxisを行うと作成できます。

#InputActionをReactivePropertyに変換する拡張メソッド

```C#:InputSystemExtension.cs
using System.Collections;
using System.Collections.Generic;
using UniRx;
using UnityEngine;
using UnityEngine.InputSystem;

public static class InputSystemExtension
{
	    public static ReadOnlyReactiveProperty<bool> GetButtonProperty(this InputAction inputAction)
	    {
		    return Observable.FromEvent<InputAction.CallbackContext>(
				    h => inputAction.performed += h,
				    h => inputAction.performed -= h)
			    .Select(x => x.ReadValueAsButton())
			    .ToReadOnlyReactiveProperty(false);
	    }
	    
	    //Axis入力だと0等が反応しないためGetDeltaAxisPropertyのみの使用でもよさそうです
	    public static ReadOnlyReactiveProperty<float> GetAxisProperty(this InputAction inputAction)
	    {
		    return Observable.FromEvent<InputAction.CallbackContext>(
				    h => inputAction.performed += h,
				    h => inputAction.performed -= h)
			    .Select(x => x.ReadValue<float>())
			    .ToReadOnlyReactiveProperty(0);
	    }

	    //Delta入力はUpdate基準なのでUpdate基準に変換(主にマウスで使用)
	    public static ReadOnlyReactiveProperty<float> GetDeltaAxisProperty(this InputAction inputAction)
	    {
		    return Observable.EveryUpdate().Select(_ => inputAction.ReadValue<float>()).ToReadOnlyReactiveProperty(0);
	    }

}
```

#テストコード

```C#:TestInput.cs
using System;
using UnityEngine;
using UnityEngine.InputSystem;
using UniRx;

public class TestInput : MonoBehaviour,IDisposable
{

    [SerializeField]
    private InputActionMap inputAction;
    
    private ReadOnlyReactiveProperty<bool> attack = default;
    //ボタンに変換したIReactivePropertyを公開
    public IReadOnlyReactiveProperty<bool> Attack => attack;
    
    private ReadOnlyReactiveProperty<float> mouseX = default;
    //Mouseの移動量に変換したIReactivePropertyを公開
    public IReadOnlyReactiveProperty<float> MouseX => mouseX;

    /// <summary>
    /// 2ボタンで-1 0 1出力
    /// </summary>
    private ReadOnlyReactiveProperty<float> horizontal = default;
    //Mouseの移動量に変換したIReactivePropertyを公開
    public IReadOnlyReactiveProperty<float> Horizontal => horizontal;
    
    private void OnEnable()
    {
        inputAction.Enable();
    }

    private void OnDisable()
    {
        inputAction.Disable();
    }
    
    private void Awake()
    {
        attack =inputAction.FindAction("Attack").GetButtonProperty();
        mouseX = inputAction.FindAction("MouseX").GetDeltaAxisProperty();
        horizontal = inputAction.FindAction("Horizontal").GetAxisProperty();
    }

    private void OnDestroy()
    {
        Dispose();
    }

    public void Dispose()
    {
        inputAction?.Dispose();
        attack?.Dispose();
        mouseX?.Dispose();
        horizontal?.Dispose();
    }
}
```

```C#:Test.cs
using UnityEngine;
using UniRx;
using UniRx.Triggers;

public class Test : MonoBehaviour
{
    [SerializeField]
    private TestInput input;

    private void Start()
    {
        input.Attack.Subscribe(x=>
        {
            if (x)
            {
                Debug.Log("GetButtonDown");
            }
            else
            {
                Debug.Log("GetButtonUp");
            }
        }).AddTo(this);

        this.UpdateAsObservable().Subscribe(_ =>
        {
            Debug.Log("GetButton:" + input.Attack.Value);
            
            Debug.Log("Horizontal"+ input.Horizontal);

            Debug.Log("MouseX" + input.MouseX);

        }).AddTo(this);        
    }
}
```

#最後に
InputSystemPackageをそのまま使用するよりは楽に使えるようになったと思います。