【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…という具合に数字が増えていくようです。
(コントローラの画像は公式画像をお借りしています)
使用するコントローラを限定すればlayoutなどでコントローラを判別する事も出来そうですね。難点は新しく発売されたコントローラに対応するためにアップデートする必要があるかもって事でしょうか。
DirectInputについては統一性がなく繋ぐコントローラによって様々なので個別で対応するのは不可能ではないかと思われます。
この場を借りてコントローラ名を調べて下さった皆さんに感謝します。