ブラウザゲームの実行環境が Flash(昔) → HTML5(今) になりつつある昨今、モダンブラウザにおいては HTML5+JavaScript でネイティブアプリ並に OpenGL やらリアルタイムオーディオといったゲームに向いてそうな処理が色々と書けるようになってきています。そんなゲーム向けのウェブAPIとしてゲームパッド入力APIが結構前から整備されてきてるのは知ってたんですけども、NOBI-CONのレビュー記事を書いた際にふと興味がわき、実際どの程度のものなのか?フライトシムみたいな凝ったデバイス接続があるケースにも対応できるのか?そこらを確認するためにデモコードを書いて実験してみました。
まずは “Gamepad API” にかんする質問をグーグル先生に色々ぶつけて集めた要点はだいたいこんな感じ。
- 2011年末あたりから Firefox と Chrome で実装が始まったらしい。
- API仕様書ドラフトはここ(英語)。日本語翻訳はここ(MDN)とか。
- ブラウザコンパチビリティ表はこことか。
- IEとSafariは未実装。Microsoft Edgeは実装済みだが制限がある(後述)。Operaでも動くみたい。
- いくつかのモバイルブラウザでも動く(互換表参照)
- ブラウザによる挙動の違いはけっこうある。
- アプリ実装方法の日本語の解説はここが大変参考になりました。有難うございます。
Gamepad API デモプログラム
私のPC環境にはフライトシム用のコントローラが複数繋がっているので、これらを正しく別々に認識し実用的(?)に入力読み取りができるかどうかを確認するため簡単なブラウザアプリを実装してみました。
以下のリンクを Gamepad API 対応のブラウザで開くと接続されているゲームパッド/ジョイスティックの個別の入力情報を確認できます。
右上のリストボックスで表示モードを選択します。”Text mode..”を選ぶと、Gamepad API で取得した生のデータをテキストで表示します。”ALL水平バー”はアナログ軸をすべて横バー表示で配列します。”レイアウトAUTO”は、アナログ軸レイアウトをプログラム側で「たぶんこんな感じ?」と推定して表示します(あまりアテにならない)。
複数デバイスが接続されてる場合、左上のリストボックスで表示したいデバイスを選択できます。Firefox の場合はセキュリティの理由からデバイスに入力があるまでデバイスを認識しませんので注意です。なお「アナログ軸を表示するには、軸を操作してください」と表示されますが、これは私のアプリ実装の都合なのでデバイス認識時点でアナログ軸もちゃんと認識されてます(Text mode で確認できます)。
Gamepad API の JavaScript による利用方法は先述の参考リンクのほか、日本語の優れた説明がいっぱいあるのでここでは説明を省き、この記事では実際に私の環境下で確認してみて気になった挙動や問題点を記述します。
対応ブラウザと互換状況
Firefox と Chrome では仕様どおりに軸やボタン情報が取得できました。Operaも動くらしいですがすんません、テストしてません。IE が駄目なのは予想してましたが、Microsoft Edge が対応してたのは意外でした。ただ、実際に試して気がついたんですが Edge は XBOX コントローラー(Xinput)しか対応しません。Xinput 対応であれば他社製品でも Gamepad API が機能します。
デバイスの対応状況
以下の手持ちデバイスを接続したり外したりしてチェックしてみました。
- CH COMBATSTICK 568 (スロットル付きジョイスティック)
- Saitek Throttle Quadrant (三軸スロットル) 2台
- CH Rudder Pedals(ラダーペダル)
- Microsoft Sidewinder precision 2 (ひねりラダー・スロットル付きジョイスティック)
- ロジクール F310 (アナログゲームパッド)
- ELECOM JC-U2208TRD(レトロ風デジタルゲームパッド)
Firefox/Chrome のどちらも普通のゲームパッドやジョイスティックならほとんど認識するようです。Microsoft Edge は前述のとおり、Xinput 対応のゲームパッドしか認識しません。フライトコントローラーは Xinput には対応していないのが普通なので、Edge ではフライトコントローラーは認識しません。
ロジクールF310は裏面に DirectInput/Xinput の切り替えスイッチがあり、Xinput モードにしないと Edge で認識しない。Firefox/Chrome では、このスイッチを切り替えるとIDが異なる別のコントローラーとして認識される。
普通のジョイスティックなら『ほとんど』認識すると書いたのは、私の環境では Firefox においてCHラダーベダルは認識しませんでした(Chrome は認識しました)。CH Product のラダーベダルはボタン無しのアナログ3軸の入力デバイスなので、当てずっぽうですがもしかするとボタンが無いデバイスを Firefox の Gamepad API は認識しないのかもしれません(そうであれば Saitek など他社のラダーペダルも認識しない可能性があるが未確認)
一方 Chrome では、どうも4台までのデバイスしか認識しないようです。たとえば スティック, スロットル x2, ラダー の4台接続に追加でゲームパッドを挿すとそれを認識しません。5台以上接続した状態で Chrome を起動すると4台までしか認識しません(4つを選ぶ規則も不明)。
CH COMBATSTICK や Sidewinder precision 2 には、フライトシムで視野制御に使う事が多いハットスイッチ(POV)がありますが、Firefox では認識されず(ボタンとしても認識しない)、 Chrome ではハットを一つのアナログ軸として認識します(フライトシムの設定で見かける2軸スタイルではない)。このハット軸の値と対応する方向にかんして仕様には記載がなく(そもそもハットスイッチのような形態を想定してるかどうかも不明)、COMBATSTICK と Sidewinder で微妙に異なる値が返ります。
具体的には CH COMBATSTICK ではリリース(真ん中)の値が -1.2857142686843872 ですが Sidewinder では 1.2857143878936768 です。ハットを入力した場合に、上方向が -1 で右上が -0.7142857313156128(つまり-1+2/7), 右は -0.4285714030265808 と時計回りで 2/7 ずつプラスされて左上が +1 であるのは COMBATSTICK と Sidewinder で共通ですが、仕様に明記されてるわけではないので他のデバイスでは異なる可能性があります(たとえば逆回りとか)。
ググる先生に聞いてみますと、デバイスによっては Firefox でもPOVを認識するが軸ではなくボタン入力として値が返ってくる場合もあるらしく、少くとも現状 Gamepad API で汎用的にハットスイッチ(POV)を扱うのはかなり面倒と言ってよいでしょう。
ロジクールの F310 を DirectInput モードにした場合 Firefox では左上の十字カーソル部分(標準ドライバではPOV軸の部分)の値がとれません。F310 は上面にある mode ボタンで十字キーと左のアナログ軸を入れ替え可能でこの時、十字キー→デジタル軸、左アナログ軸→デジタル4ボタンになりますが、この入れ替え状態にすると十字キーはデジタル軸として入力できる一方、今度は左アナログ軸のボタン入力が取れません。なお Xinput モードの場合は Firefox でも Chrome と同じようにちゃんと入力を取れます。
ロジクール F310 の奥側にある LT/RT ボタン(ボタン#5,#6)は Xinput モードにすると押し込みのアナログ値が取れるボタンですが、Firefox ではアナログ値は取れずデジタル On/Off の値になります。Chrome ではちゃんとアナログ値を取れます。アナログ押し込みボタンのあるコントローラーの手持ちはこれしかないので、他のコントローラーでどうなってるかは不明です(情報求む!)
ロジクールF310 のトリガーボタン押し込みアナログ値は Firefox では取得できなかった。
軸とボタンのマッピング
ボタンや軸の機能の割り当て情報(マッピング)について Gamepad API では gamepad オブジェクトの mapping プロパティで取得できるようになっています。しかしながら現状このマッピング情報は「とりあえず用意してみた」レベルでほとんど役に立ちません。返ってくる値は “”(空文字) か “standard” しかなく、”standard” だと Xbox 風コントローラの Gamepad API 標準割り当てマッピングである、ということがわかるだけです。
gamepad オブジェクトの id プロパティは、デバイス名称/ベンダーID/プロダクトIDを合成した文字列になっています(仕様で決まってるわけではないので注意…例えば Firefox と Chrome で合成フォーマットが違うし、デバイスの抜き挿しを繰り返したりするとたまに謎文字列になる場合がある…)。ちゃんとゲームパッド対応したいなら、id から有名なデバイスは判別してプリセットマッピングを用意しておき、プログラム上でユーザーマッピングを用意するような仕組みは必須と思われます。
ボタン連打について
今回の記事のデモプログラムではチェックできませんが、ブラウザゲームに実装して色々試してみたところ Firefox ではボタン連打の検知に限界があるようです(あらし君や高橋名人じゃなくても到達可能なレベルの限界)。ゲームパッド/ジョイスティックの入力はハードウェアに近い層でも通常イベント通知(割り込み)ではなくポーリングによる読み出しになりますが、どうやら Firefox の Gamepad API 内部のポーリングサイクルがかなり荒いようで毎秒10連打とかは無理なようです。Firefox ではゲームパッドでボタン連打を前提するゲームの実装は諦めたほうがよさそうです(キーやタッチパネル併用のインターフェイスならOK)。
まとめ
2018年8月現在、様々なアナログ・コントローラーを複数接続した環境を使うゲーム(フライトシムみたいなの)に対応するのはかなり困難と思われます。XY移動とボタンをまばらに押す感じのゲームなら可、ぐらいの感じでしょうか(まあブラウザゲームってそんなもんでしょ、という意見は…横に置く)。
現状はあくまで実験段階の機能であって今後整備や挙動の統一など図られていくとは思いますが、マニアの多いPCゲームでもフライトコントローラーやハンドルコントローラーまで揃えてプレイしてる人はマイノリティなためか、”ゲーム用のコントローラー、すわなちXBOX風のゲームパッド”のイメージでAPI仕様が決め打ちされてしまってるような感があり、やや不安が残ります。