MGL週報 #41 - Steamのゲームパッド対応あれこれ
このエントリはゲーム開発用フレームワーク「MGL」の開発記録です。MGLはzlibライセンスの下に無償で提供されています。
ドキュメントはこちら
進捗状況の確認と問い合わせはこちら
今週の作業内容
ByteStreamあれこれ
先週発覚したエラー発生時の挙動が統一されていない問題を解決して、それに伴いドキュメントを書き直し。これにて本件はひとまず完了しました。
が、他にも直したい部分がちらほら出てきたり。やっぱり例外を投げるバージョンが欲しいとか、名前空間的にMemory以下に配置した方が良いよねとか。前者はともかく、後者はエクステンションに影響が出そうなんですよね。
あと、1週間の作業内容がこれだけというのはさすがに問題。善処せねば。
Steamのゲームパッド対応あれこれ
もう結構前になりますが、Steamではゲームコントローラの対応状況の表記がより細分化されました。
この対応により、例えばDualShock4やDualSenseなどのPS系のコントローラに対応していますよとストアに表記したい場合、「A」や「B」の代わりに「×」や「○」を表示できるようにしなければなりません。これを実現するにはデバイスの種類を認識するための仕組みが必要です。
残念な事に、MGLでは現在これを完全に満たせる機能を提供できていません。何故なら、Windowsではデバイスの種類を特定することができないのです。
という訳で、ちょっとその辺のうんちくを語る事にしましょう。
MGLのゲームパッドまわりの仕組み
とりあえず、MGLがどんな仕組みでゲームパッドを扱っているかを述べておきましょう。
……の前に1つ。MGLではゲームコントローラの呼称や表記を極力「ゲームパッド」(Gamepad)で統一しています。これは広義のゲームコントローラとの混同を避けるためです。以降の解説も基本的には「ゲームパッド」の表記を使用しますが、製品名のような固有名詞はその限りでは無い点にご注意ください。
さて、MGLのゲームパッドまわりの実装を概略図で表すと次のような感じになります。
MGLでは「ゲームパッドサーバ」なるものがバックグラウンドで動作していて、接続されているデバイスの監視や入力情報の更新などを担っています。しかし、実際にデバイスと通信を行い入力状態を取得するのはOSやドライバといったシステム側のお仕事です。一般的には、ゲームパッドの入力状態はシステム側で用意されたAPIを通して行います。例えば、WindowsであればXInputやDirectInput、macOSならGameControllerフレームワークやIOKitです。(IOKitはちょっと特殊ですが、その辺は割愛)
MGLは環境に依存しないフレームワークですので、ゲームパッドサーバがシステムに依存したAPIを直接呼び出したりはしていません。その代わりに、特定のAPIを用いて実装するための「ゲームパッドデリゲート」が登録可能となっています。ゲームパッドサーバは登録されているデリゲートに対して情報の更新を要求し、デリゲートによって更新された情報をゲーム側に伝えるという仕組みです。
もちろん、登録するデリゲートはアプリケーション側から好きなように追加や選択ができます。デリゲートを介することで、MGLはあらゆるものをゲームパッドとして扱えるようになります。それは独自の入力デバイスだけでなく、画面タッチやネットワーク越しの入力エミュレーションなどにも柔軟に対応できます。この辺がMGLが売りにしているカスタマイズ性の特徴ですね。
XInputについて
さて、今回の問題点は認識したゲームパッドデバイスの種類を特定できない事でしたね。この原因はXInputの仕様、ひいてはその生い立ちに関わっているのです。
XInputはそれまで使用されていたDirectInputに代わるAPIとして登場しました。その理由については色々と囁かれたたりもしましたが、最大の理由は仕様を統一することでした。
DirectInputの時代というのは統一されたルールのない混沌期でした。製品によってボタンの配置や数がバラバラであり、それをアプリケーション側から知る手段もないため、ゲームとデバイスとの相性問題というのもしばしば発生していました。これはゲーム開発者としても悩みの種です。そこで、当時のXbox360コントローラを標準のゲームパッドとし、それを扱うために登場したのがXInputです。
以降、XInputをWindowsにおける標準のゲームパッド入力取得APIとして位置付け、DirectInputは互換性のために存在するレガシーAPIとしています。当初は対応デバイスがXbox360コントローラくらいしかなく、機能も削減されているため普及の足枷になったりもしていましたが、今日では最も標準的なAPIであると言っても差し支えないでしょう。
と、ここまでのうんちく話で「デバイスの種類を特定できない理由」に気付いた方は鋭いかもしれません。XInputはXbox360コントローラに準拠したデバイスを扱うためのAPIですので、そもそも種類を特定する必要は無いし、それがメリットなのです。そして、鋭い方は同時に混乱もしているかもしれません。何故それを特定する必要があるのか、と。
Steamのオーバーライド機能
XInputはXbox準拠のAPIのはずなのに、その他のゲームパッドもXInputで認識できると経験している方は多いかもしれません。例えば、私がSteamで配信している「反撃BLOCKS」はXInputとDirectInputに対応していますが、PS4やNintendo Switchのゲームパッドを接続するとXInputとして認識されます。
実はこれは、XInputやアプリケーション側で対応しているものではなく、Steamの機能の一部なのです。WindowsのSteamには、XInputをオーバーライドし、本来対応していないデバイスを無理やりXInputに認識させる機能が備わっているのです。この機能は自動的に有効化されるため、開発者でも知らなかったという方は多いかもしれません。かく言う私もDirectInputと干渉する不具合を踏むまで気付きませんでした。
そう、本来のルールを捻じ曲げているのはSteamなのです。ですので、それをリカバリするための機能もやはりSteam側にあります。SteamworksAPIには指定したインデックスのXInputデバイスの詳細を取得するAPIがあり、それを利用して製品の種類を特定し、ボタンの表記などの差異を解決するのです。
ですが、MGLの標準構成にはSteamの機能は含まれていません。これが最初に述べた「完全に満たせる機能を提供できていない」理由です。Windowsではどのようなデバイスを接続しても、XInput経由で認識されている限りXbox準拠のデバイスとして認識されてしまうのです。
対処法
この問題に対してアプリケーション側から解決を図ることも不可能ではありません。しかし、やはりMGL側のデリゲートで解決するのが最もスマートである事に疑う余地はないでしょう。
そこで登場するのが、色々と中途半端で公開に至っていないSteamworks対応エクステンションでしょうか。
このエクステンションは、導入するだけでSteam対応の面倒なあれこれをおおよそ解決してくれるものです。実際に「ぺぐそり+」での使用実績はあるのですが、細かい部分で検証が不足しているため公開に至っていません。将来このエクステンションを公開する際に、ついでにゲームパッドの問題の解決も盛り込もうかと考えています。
が、いかんせん「検証」が最大の壁なのですよね。その機能を使うタイトルをもう1つ2つリリースしてからとしたいのですが、一体それは何年後になる事やら……
とりあえず方針は決まっているので、早いうちにこれを実現できるよう画策しています。そのあたりはまた後日。
その他
何だか長いうんちく話になってしまった。
この記事が気に入ったらサポートをしてみませんか?