JavaScriptでゲームパッド対応を実装した話

ブラウザゲームのコントローラー入力をリバースエンジニアリングするために、週末を丸ごと費やしました。深夜2時、私は空の配列をただ見つめていました。何も表示されなかったのです。

その経験から、どんなチュートリアルよりもブラウザAPIとハードウェアポーリングについて多くのことを学びました。

ウェブゲームは成長しています。WebGLやWebGPUの登場により、ブラウザゲームは今や非常に高いクオリティに達しています。プレイヤーは、XboxやPS5のコントローラーを接続すれば、すぐに使えるようになることを期待しています。

ゲーム、アクセシビリティツール、あるいはカスタムダッシュボードを開発しているなら、HTML5 Gamepad APIが必要です。これはChrome、Firefox、Edgeで動作し、ライブラリも必要ありません。

学んだことは以下の通りです:

  • APIは接続に関してはイベント駆動型ですが、入力に関してはポーリングベースです。
  • 入力を継続的に読み取るには、requestAnimationFrameを使用する必要があります。
  • ユーザーがボタンを押すまで、ブラウザはコントローラーを表示しません。これはハードウェア・フィンガープリントを防ぐためのプライバシー機能です。

データの管理:

  • gamepad.mappingを使用して「standard」レイアウトかどうかを確認します。標準マッピングを使用すれば、ボタン0が常に下側のフェイスボタンであることを保証できます。
  • gamepad.idを確認して、ベンダーIDとプロダクトIDを特定します。これにより、Sony DualSenseのような特定のハードウェアを識別できます。
  • 常にデッドゾーン・フィルターを実装してください。アナログスティックが完全に中央に止まることはありません。デッドゾーンがないと、キャラクターやカメラが常にドリフトしてしまいます。

デッドゾーンを処理する簡単な方法: Math.abs(axis) > 0.1 であれば、その値を使用する。

ハプティックフィードバック: gamepad.vibrationActuator.playEffectを使用して、振動を発生させることができます。これはChromeとEdgeでうまく動作します。Firefoxは部分的にサポートしていますが、Safariはサポートしていません。

プロジェクトにおける重要なポイント:

  • gamepadconnectedgamepaddisconnected イベントをリッスンします。
  • 「押し下げ(press)」と「長押し(hold)」を区別するために、前回のボタンの状態を追跡します。
  • スティックの微細な動きを無視するために、デッドゾーンのしきい値を使用します。
  • 複数のブラウザでテストしてください。
  • navigator.getGamepads() はスナップショットを返すということを忘れないでください。最新のデータを取得するには、ループ内でこれを呼び出す必要があります。

コードを書く前にハードウェアをテストしたい場合は、GamepadTester.proを使用してください。生のAPIデータと軸の値をリアルタイムで表示してくれます。

出典: https://dev.to/grezalazar23453/i-built-gamepad-support-into-my-web-app-using-pure-javascript-heres-everything-i-learned-51a5