【Unity】Input Systemでバーチャルパッドを実装する

こじゃらこじゃら

スマホのバーチャルパッドを簡単に実装する方法を知りたいの…

このはこのは

Input Systemを使えば簡単だわ。今回はOn-screen Controlsを使ってこの辺を実現する方法を教えるね。

Input Systemを使用してバーチャルパッドを実装する方法の紹介です。

これはInput Systemが提供する機能であるOn-screen Controlsを用いると楽に実装できます。

参考:On-screen Controls | Input System | 1.3.0

On-screen Controls最大の特徴は、バーチャルパッドのボタンやスティックなどの操作をデバイス入力値に直に反映させる点です。

On-screen Controlsにはボタン入力のOn-screen buttons、スティック入力のOn-screen sticksが予め用意されていますが、独自のカスタムコントロールを作ることも可能です。

本記事では、On-screen Controlsを用いてバーチャルパッドの入力を受け取る方法について解説していきます。

動作環境
  • Unity 2021.2.19f1
  • Input System 1.3.0

スポンサーリンク

前提条件

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

ここまでの手順が分からない方は、以下記事をご覧ください。

バーチャルパッドと連携する仕組み

バーチャルパッドのボタンやスティックの操作入力をキーボードやゲームパッドなどのデバイス入力(Control Path)に反映させることで実現します。

例えば、画面上のボタンが押されたとき、ゲームパッドやキーボードのボタンが押されたことにするといった動きを実現できます。

Control Pathとは

デバイスのボタンやスティックなどを表す文字列です。

例えば、キーボードのAキーなら<Keyboard>/a、ゲームパッドの左スティックなら<GamePad>/LeftStickという表現になります。

参考:Controls | Input System | 1.3.0

ボタンの実装例

キャラクターのジャンプボタンを例に取って、実際に機能させるところまでを解説します。

実装手順の流れは次のようになります。

ボタンの実装手順
  • uGUI Buttonを画面上に配置
  • ボタンオブジェクトにOn-screen Buttonコンポーネントをアタッチ
  • Control Pathを設定

本記事では、uGUIの空CanvasにUIを配置していくところから解説していきます。

ボタンの配置

ヒエラルキーウィンドウのCanvasオブジェクトを右クリックし、UI > Button – TextMeshProの順に選択し、ボタンをCanvas上に配置します。

Text Mesh Pro未インストールの環境の場合、TMP Importerウィンドウが表示されるため、Import TMP EssentialsボタンをクリックしてText Mesh Proをインストールしてください。

必要に応じてテキストやレイアウトなどを調整しておきましょう。

On-screen Buttonコンポーネントのアタッチ

配置したボタンにOn-screen Buttonコンポーネントをアタッチします。

Control Pathの設定

ボタンが押されたときに入力を反映させたいデバイスのControl Pathを設定します。

例では、キーボードのスペースキーを設定するものとします。

正しく設定すると、以下のようにControl Typeにパスが設定されているのを確認できます。

キーボード入力を受け取る準備(テスト用)

動作確認のため、ジャンプ入力を受け取るスクリプトをアタッチし、正しく動作しているかどうかを確認します。本手順はテスト用のため、必須ではありません。

JumpButtonTest.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class JumpButtonTest : MonoBehaviour
{
    private void Update()
    {
        // 現在のキーボード情報
        var current = Keyboard.current;

        // キーボード接続チェック
        if (current == null)
            return;

        // スペースキーが押された瞬間かどうか
        if (current.spaceKey.wasPressedThisFrame)
            Debug.Log("スペースキーが押された!");
    }
}

このスクリプトをJumpButtonTest.csという名前でUnityプロジェクトに保存し、適当なゲームオブジェクトにアタッチすると機能するようになります。

実行結果

ここまでの手順を成功させると、ボタンを押下した瞬間にジャンプ入力されるようになります。

キーボードのスペースキー入力を直で参照しても、確かにボタン操作が反映されています。

ジョイスティックの実装例

バーチャルジョイスティックは、On-screen Stickを用いて実現できます。

実装の流れは以下の通りです。

スティックの実装手順
  • スティックの画像オブジェクトを画面上に配置
  • オブジェクトにOn-screen Stickコンポーネントをアタッチ
  • 可動範囲、Control Pathを設定

ボタンと実装の要領は一緒ですが、スティックの可動範囲の設定が増えています。

画像オブジェクトの配置

本記事では、キャラクター移動用のバーチャルジョイスティックを実装するものとします。ドラッグ可能なオブジェクトであれば何でも構いませんが、本記事ではノブ画像を用いることとします。

次のように可動範囲とスティックを重ねて配置しました。

On-screen Stickコンポーネントのアタッチ

ノブ部分のオブジェクトにOn-screen Stickコンポーネントをアタッチします。

可動範囲、Control Pathの設定

インスペクターよりOn-screen Stickの設定を行います。

Control Typeのほか、Movement Range項目にスティックの可動範囲をピクセル単位で指定します。 [1]

スティック入力を受け取る準備(テスト用)

ボタンの例と同じように、スティック入力を受け取るためのテストスクリプトを用意するものとします。テスト用なので、必須ではありません。

LeftStickTest.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class LeftStickTest : MonoBehaviour
{
    private void Update()
    {
        // 現在のゲームパッド情報
        var current = Gamepad.current;

        // ゲームパッド接続チェック
        if (current == null)
            return;

        // 左スティック入力取得
        var leftStickValue = current.leftStick.ReadValue();
        Debug.Log($"移動量:{leftStickValue}");
    }
}

左スティック入力を受け取るものとしました。本スクリプトをLeftStickTest.csという名前で保存し、適当なゲームオブジェクトにアタッチすると機能します。

実行結果

バーチャルジョイスティックとして機能するようになりました。

ノブ部分がドラッグ操作によって動いていることが確認できます。この辺のUI制御処理もOn-screen Stickが行ってくれます。

カスタムコントロールの実装

ボタンやスティック以外のUI、3Dオブジェクトなどを操作対象に出来るようになります。

カスタムコントロールの実装の流れは以下の通りです。

実装の流れ
  • OnScreenControl継承クラスをスクリプトで定義
  • Control Pathを返すプロパティを実装
  • 操作されたときに入力値を変化させる処理を実装

順番に解説していきます。

完成スクリプトの実装例

uGUIのスライダーのカスタムコントロールを実装した例を示します。

OnScreenSlider.cs
using UnityEngine;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.OnScreen;
using UnityEngine.UI;

[RequireComponent(typeof(Slider))]
public class OnScreenSlider : OnScreenControl
{
    // 参照先のスライダー
    private Slider _slider;

    private void Awake()
    {
        // 初期化時に、スライダー操作のイベントリスナ登録
        _slider = GetComponent<Slider>();
        _slider.onValueChanged.AddListener(OnValueChanged);
    }

    // スライダーが操作されたときに呼ばれるイベント
    private void OnValueChanged(float value)
    {
        // ここでControl Pathの入力値を変更する
        SendValueToControl(value);
    }

    // Control Pathの文字列を格納するフィールド
    [InputControl(layout = "Button"), SerializeField]
    private string _controlPath;

    // Control Pathを返すプロパティ
    // ここで返すパスに入力値が上書きされる
    protected override string controlPathInternal
    {
        get => _controlPath;
        set => _controlPath = value;
    }
}

上記スクリプトをスライダーオブジェクトにアタッチすると機能するようになります。

入力を受け取るテストスクリプトは次のようにしました。入力デバイスは必要に応じて変えてください。

SliderInputTest.cs
using UnityEngine;
using UnityEngine.InputSystem;

public class SliderInputTest : MonoBehaviour
{
    private void Update()
    {
        // 現在のゲームパッド情報
        var current = Gamepad.current;

        // ゲームパッド接続チェック
        if (current == null)
            return;

        // 右トリガー入力取得
        var sliderValue = current.rightTrigger.ReadValue();
        Debug.Log($"スライダー:{sliderValue}");
    }
}

実行結果

スクリプトの解説

カスタムコントロールクラスの定義は、OnScreenControlクラスを継承することで行います。

public class OnScreenSlider : OnScreenControl

参考:Class OnScreenControl | Input System | 1.3.0

uGUIのスライダーの値変更の検知は以下コードで行っています。

// 参照先のスライダー
private Slider _slider;

private void Awake()
{
    // 初期化時に、スライダー操作のイベントリスナ登録
    _slider = GetComponent<Slider>();
    _slider.onValueChanged.AddListener(OnValueChanged);
}

参考:Class Slider | Unity UI | 1.0.0

Input Systemの入力値の上書きは、SendValueToControl()メソッド呼び出しで行います。

// スライダーが操作されたときに呼ばれるイベント
private void OnValueChanged(float value)
{
    // ここでControl Pathの入力値を変更する
    SendValueToControl(value);
}

参考:Class OnScreenControl | Input System | 1.3.0

Control Pathをインスペクターから設定できるようにするために、次のようにシリアライズされるフィールドを定義します。

// Control Pathの文字列を格納するフィールド
[InputControl(layout = "Button"), SerializeField]
private string _controlPath;

InputControl属性を付加することで、Control Pathを入力する専用のUIに置き換わります。

参考:Class InputControlAttribute | Input System | 1.3.0

そして、上記Control Pathを返すcontrolPathInternalプロパティを実装します。 [2]

// Control Pathを返すプロパティ
// ここで返すパスに入力値が上書きされる
protected override string controlPathInternal
{
    get => _controlPath;
    set => _controlPath = value;
}

さいごに

Input SystemのOn-screen Controlsを用いると、バーチャルパッドとInput Systemとの連携が簡単にできるようになります。

本機能はInput Actionは用いず、デバイスのControl Pathに対して直接入力値を流し込むといった特徴があります。

カスタムコントロールを実装すると、UI以外にも3Dのボタンや仕掛けを動かしたときに入力したことにするなど、面白いことが出来るかもしれません。

Unity公式のアセットであるStarter Assetsでも、バーチャルパッドを実装したサンプルがありますので、興味がある方は参考にしてみてください。

関連記事

参考サイト

スポンサーリンク