見出し画像

【Input System】使用しているコントローラでボタン表記を自動で変更する【Unity】

Windows用のゲームで使用出来るコントローラはXInput/DirectInput/キーボード&マウスになるかと思います。ここで問題になるのが「Aボタンで決定」みたいな表示を出す時に使用しているコントローラによってボタン表記が変わる事。
使用しているコントローラによって自動でボタン表記を変更出来ないかと思ってお試しでプログラムを作ってみました。

このプログラムを作成する為に下記サイト様の記事を参考にさせて頂きました。この場を借りてお礼申し上げます。
【Unity】Input Systemでガイド用のボタンアイコンを出す

JoyStick Test2 Ver1.0.0
本プログラムを使用したことで発生した如何なる不都合に対して、
作者は責任を追いかねますのであらかじめご了承ください。
不具合などがありましたらご報告頂けると幸いです。
https://drive.google.com/file/d/1vfDILEh8lXqY8cNquw93-Po8wdmdn5Tl/view?usp=drive_link

Unityの場合はXInputのコントローラはXBOX系、プレイステーション系、Switchプロコン系に分ける事が出来るので最後に触ったデバイスがCurrentControllerに表示されるようになっています。(Joy-ConはUnityが対応していないので振り分け不可)

DirectInputコントローラについては種類がありすぎて対応するのは不可能なので纏めてDirectInput系と表示しています。

振り分けのスクリプトはこんな感じ。

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.DualShock;
using UnityEngine.InputSystem.XInput;
using UnityEngine.InputSystem.Switch;
using UnityEngine.InputSystem.Utilities;

public class Joystick_test : MonoBehaviour
{
    private InputControl inputControl;//inputControl受け取り
    private string deviceIconGroup;//コントローラの種類をまとめる
    private int controller_deviceId;//デバイスID

    void Update()
    {
        InputSystem.onAnyButtonPress.CallOnce(ctrl => inputControl = ctrl);//入力受付。入力されたキーをinputControlに入力する

        if (inputControl != null)//キー入力があったらコントローラを判別する
        {
            controller_deviceId = inputControl.device.deviceId;//デバイスID入力
            deviceIconGroup = GetDeviceIconGroup(inputControl.device);//接続されているコントローラの種類をdeviceIconGroupに代入(複雑な名前を抽象化して入力)

            if (deviceIconGroup == "Keyboard") Debug.Log("Keyboard");//キーボード

            if (deviceIconGroup == "Mouse") Debug.Log("Mouse");//マウス

            if (deviceIconGroup == "Joystick") Debug.Log("Joystick");//ジョイスティック(DirectInput)

            if (deviceIconGroup == "XInputController" || deviceIconGroup == "DualShockGamepad" || deviceIconGroup == "SwitchProController")//ゲームパッド(Xinput)
            {
                for (int i = 0; i < Gamepad.all.Count; i++)
                {
                    if (Gamepad.all[i].deviceId == controller_deviceId)
                    {
                        if (deviceIconGroup == "XInputController") Debug.Log("XInputController");//XBOX

                        if (deviceIconGroup == "DualShockGamepad") Debug.Log("DualShockGamepad");//PlayStation

                        if (deviceIconGroup == "SwitchProController") Debug.Log("SwitchProController");//Switchプロコン
                    }
                }
            }
            inputControl = null;
        }
    }

    //色んなコントローラ名をまとめる
    // "DualShock4GamepadHID"とか"DualSenceGamepadHID"みたいな名前を"DualShockGamepad"に抽象化して判別しやすくする
    private string GetDeviceIconGroup(InputDevice device)
    {
        return device switch
        {
            Keyboard => "Keyboard",
            Mouse => "Mouse",
            Joystick => "Joystick",
            XInputController => "XInputController",
            DualShockGamepad => "DualShockGamepad",
            SwitchProControllerHID => "SwitchProController",
            _ => null
        };
    }
}

このスクリプトを適当なゲームオブジェクトに張り付けて実行するとデバックログに使用したコントローラの種類が表示されると思います。

InputSystem.onAnyButtonPressを使うと全てのデバイスの押されたキーを取得出来るのでそれをInputControlに入力すると、押されたキーのデバイスIDや名前やパスなどの様々な情報を知る事が出来るので、それを使って使用されたデバイス名を抽象化して判別する感じです。
(inputControl.device.nameなら名前、inputControl.device.deviceIdならデバイスID、inputControl.device.pathならボタンパスみたいな感じで取得出来ます)

InputSystem.onAnyButtonPressはスティック入力は感知出来ないので、スティックでの入力でも判別したい場合はGamepad.current(DirectInputならJoystick.current)で現在使用しているゲームパッドを取得出来るので、そちらから判別してInputSystem.onAnyButtonPressとGamepad.currentの両方で判別するのが良い方法かなと思いました。

       //inputControlではスティックの入力は取得出来ないのでGamepad.currentで取得する
        var gamepad = Gamepad.current;//現在のゲームパッド
        if (gamepad == null) return;

        var leftStick = gamepad.leftStick.ReadValue();//左スティック取得
        var rightStick = gamepad.rightStick.ReadValue();//右スティック取得

        if (leftStick.magnitude > 0.3f || rightStick.magnitude > 0.3f)
        {
            inputControl = null;//スティックを優先するためnullする。(nullしないとinputControlの値が参照されてしまう)

            controller_deviceId = gamepad.deviceId;//デバイスID入力

            deviceIconGroup = GetDeviceIconGroup(gamepad.device);//接続されているコントローラの種類をdeviceIconGroupに代入(複雑な名前を省略して入力)
            if (deviceIconGroup == "XInputController") Debug.Log("XInputController");//XBOX

            if (deviceIconGroup == "DualShockGamepad") Debug.Log("DualShockGamepad");//PlayStation

            if (deviceIconGroup == "SwitchProController") Debug.Log("SwitchProController");//Switchプロコン
        }

InputSystem.onAnyButtonPressを使用せずにGamepad.currentを使用してボタンの判別をする方法もあると思うのですが、使用するデバイスによって何も入力していないのに反応するコントローラがあるようで、出来れば使わない方が良いかもしれません。(もし上記ソフトを使用されてXInput系で常に反応するようなコントローラがあればご報告頂けると嬉しいです)

各コントローラのdisplayNameとlayoutを表記しておきます。ちなみにlayoutとnameはほぼ同じになるのですが同じ名前があると例えばlayoutがXInputControllerWindowsだとするとnameはXInputControllerWindows1,XInputControllerWindows2,XInputControllerWindows3…という具合に数字が増えていくようです。
(コントローラの画像は公式画像をお借りしています)


XBOX ONEに付属のコントローラ

displayName = Xbox Controller

layout = XInputControllerWindows


XBOX 360 コントローラ

displayName = Xbox Controller

layout = XInputControllerWindows


Xbox series X|S 付属コントローラ

displayName = Xbox Controller

layout = XInputControllerWindows


DualShock4

displayName = Wireless Controller

layout = DualShock4GamepadHID


DualSence

displayName = DualSence Wireless Controller

layout = DualSenceGamepadHID


DualShock3(not SIXAXIS)

displayName = PLAYSTATION(R)3 Controller

layout = DualShock3GamepadHID

※DualShock3はそのままだとWindowsでは使用出来ない。
使用出来るソフトなどを使用するとXInputControllerWindowsとして認識される模様


Switchプロコントローラー(Bluetooth接続)

displayName =Wireless Gamepad

layout = SwitchProControllerHID

※USBケーブル接続時はdisplayNameはPro ControllerとなるがWindowsでは使用出来ない?

使用するコントローラを限定すればlayoutなどでコントローラを判別する事も出来そうですね。難点は新しく発売されたコントローラに対応するためにアップデートする必要があるかもって事でしょうか。

DirectInputについては統一性がなく繋ぐコントローラによって様々なので個別で対応するのは不可能ではないかと思われます。

この場を借りてコントローラ名を調べて下さった皆さんに感謝します。

いいなと思ったら応援しよう!