【Unity】新しいInput SystemのOn-Screen Controlsでタッチスクリーン上にジョイスティックやボタンを作る

新しいInput SystemのOn-Screen Controlsでタッチスクリーン上にジョイスティックやボタンを作る方法をまとめました。

Unity2020.1
Input System 1.0.0

はじめに

本記事ではUnity2020のリリースと同時にVerifiedとなった新しいInput SystemのOn-Screen Controlsの使い方についてまとめます。
On-Screen Controlsはタッチスクリーン上に仮想的なボタンやジョイスティックを作るための機能です。

なおInput Systemの基礎知識については以下の記事にまとめていますので、必要に応じて参照してください。

light11.hatenadiary.com

On-Screen Button

さてそれでは実際に仮想的なボタンを作ってみます。
ボタンを作るにはまずuGUIで適当にButtonを作ります。

f:id:halya_11:20200818232434p:plain
uGUIのボタン

次にこのGameObjectにOnScreenButtonコンポーネントをアタッチします。
Control Pathにはこの仮想的なボタンが押されたときに呼び出されたことにするデバイスのボタンを指定します。
今回はGamePadのSouthボタンが呼ばれたものとみなす設定にしました。

f:id:halya_11:20200818232748p:plain
OnScreenButtonをアタッチ

あとはこの入力を受け取るためのActionを作ります。
今回は以下のようにInputActionを持つMonoBehaviourを作りました(本当はちゃんとInput Actionアセットを作ったほうがいいです)。

using UnityEngine;
using UnityEngine.InputSystem;

public class OnScreenExample : MonoBehaviour
{
    [SerializeField] private InputAction _fireAction;

    private void Start()
    {
        _fireAction.performed += _ => Debug.Log("Fire");
    }
    
    private void OnEnable()
    {
        _fireAction.Enable();
    }

    private void OnDisable()
    {
        _fireAction.Disable();
    }

    private void OnDestroy()
    {
        _fireAction.Dispose();
    }
}

そしてこのコンポーネントのInspectorからActionにGamePadのSouthボタンのバインディングを追加します。

f:id:halya_11:20200818233306p:plain
Button Southを追加

これで再生して仮想的なボタンを押すと、正常にログが出力できることが確認できます。

f:id:halya_11:20200818233854p:plain
ログ出力

On-Screen Stick

次に仮想的なジョイスティックを作ります。
まずuGUIで適当なImageを作っておきます。

f:id:halya_11:20200818234127p:plain
Image

そしてこのGameObjectにOnScreenStickコンポーネントをアタッチします。
Control Pathは Left Stick[GamePad] に設定しておきます。

f:id:halya_11:20200818234250p:plain
On-Screen Stick

この時点で再生するとuGUIが仮想スティックのように動くことが確認できます。

f:id:halya_11:20200818234556g:plain
仮想スティック

あとはボタンと同様入力を受け取るためのActionを作ります。
まずスクリプトは以下のように書きます。

using UnityEngine;
using UnityEngine.InputSystem;

public class OnScreenExample : MonoBehaviour
{
    [SerializeField] private InputAction _moveAction;

    private void Start()
    {
        _moveAction.performed += _ =>
        {
            var value = _moveAction.ReadValue<Vector2>();
            Debug.Log($"Move: ({value.x}, {value.y})");
        };
    }
    
    private void OnEnable()
    {
        _moveAction.Enable();
    }

    private void OnDisable()
    {
        _moveAction.Disable();
    }

    private void OnDestroy()
    {
        _moveAction.Dispose();
    }
}

Inspectorの設定は以下のようにします。
2DのVector型で設定しているのと、CompositeのModeをAnalogにしている点に注意してください。

f:id:halya_11:20200819001429p:plain
Inspectorの設定

この状態で実行してスティックを動かすと正常にログが出力されることを確認できます。

f:id:halya_11:20200819001756p:plain
ログ出力

自前のOn-Screen Controlsを作成する

下記のようにOnScreenControlクラスを継承すると自前のOn-Screen Controlを作成することができます。

using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.OnScreen;

[AddComponentMenu("Input/On-Screen Button")]
public class OnScreenButtonCustom : OnScreenControl, IPointerDownHandler, IPointerUpHandler
{
    public void OnPointerUp(PointerEventData data)
    {
        SendValueToControl(0.0f);
    }

    public void OnPointerDown(PointerEventData data)
    {
        SendValueToControl(1.0f);
    }

    [InputControl(layout = "Button")]
    [SerializeField]
    private string m_ControlPath;

    protected override string controlPathInternal
    {
        get => m_ControlPath;
        set => m_ControlPath = value;
    }
}

難しいことはないので説明は割愛しますが、詳しく知りたい場合にはOnScreenButtonやOnScreenStickのコードを見るのが良いかと思います。

参考

docs.unity3d.com