Nintendo Switch Pro コントローラーで、Phaserのブラウザゲームを操作する方法
JavaScript製ブラウザゲームフレームワークであるPhaserには、Gamepad APIが存在しています。
このAPIを使うことでPCに接続されたコントローラーを使用して、ブラウザゲームを操作できます。
今回は、Nintendo Switch Pro コントローラーをPCに接続し、Phaserのブラウザゲームを操作してみます。
成果物
- デモURL:https://t-tonyo-maru.github.io/pub_game_phaser_nintendo-switch-pro-controller_test/
- リポジトリURL:https://github.com/t-tonyo-maru/pub_game_phaser_nintendo-switch-pro-controller_test
Nintendo Switch Pro コントローラーを介して東北きりたんを操作できます。
動作確認方法
- USBケーブルまたはBluetoothで、Nintendo Switch Pro コントローラーをPCに接続します。
- 動作保証のため、PCに接続するコントローラーは、Nintendo Switch Pro コントローラー1台のみにしてください。
- 上記のデモURLを開きます。
- 画面表示後、Nintendo Switch Pro コントローラーの任意のボタンを押下することで、コントローラーの接続イベント(
connected
)が発火します。 - 接続イベント発火後は、Nintendo Switch Pro コントローラーの操作を受け付けるようになります。十字カーソルで東北きりたんを操作できます。
- 画面右下の「Toggle Control」を押下すると、十字カーソル操作から左スティック操作に切り替わります。
- 操作中のボタン状態は、画面右上のNintendo Switch Pro コントローラーのマッピングされます。
ソースコード解説
要点を絞って解説していきます。
GamePad APIの有効化
まずはじめに、PhaserのGameConfigにあるinput.gamepad
をtrue
に設定して、GamePad APIを有効にします。
> src/config.ts
import Phaser from 'phaser';
import { MainScene } from './scenes/mainScene/mainScene';
export const config: Phaser.Types.Core.GameConfig = {
type: Phaser.AUTO,
scale: {
// 省略
},
physics: {
// 省略
},
input: {
gamepad: true // GamePad APIを有効化
},
scene: [MainScene]
};
Nintendo Switch Pro コントローラーとの接続
Phaser.Sceneのcreate関数内で、this.input.gamepad
を利用して、コントローラーとの接続を試みます。
this.input.gamepad.once('connected', (pad) => {…})
の形式で設定します。
> src/scenes/mainScene/mainScene.ts
コントローラーと正しく接続できた後は、各ボタン操作時のイベントをセットしていきます。
コントローラー接続時のコールバック関数の引数pad: Phaser.Input.Gamepad.Gamepad
を利用して、ボタン押下時はdown
イベント。ボタンを離すときはup
イベントを設定します。
あとは、down
イベント、up
イベントのコールバック関数に、具体的な処理を実装していくだけですね。
this.input.gamepad.once(
'connected',
(pad: Phaser.Input.Gamepad.Gamepad) => {
this.pad = pad; // 接続したコントローラーを保持
// ボタン押下時のイベントをセット
pad.on('down', (buttonCode: number) => {
this.renderControllerButtonStatusText(buttonCode, true);
this.renderControllerButtonImage(buttonCode, true);
if (!this.isLStickControl) {
this.movePlayerWithCursor(buttonCode, true);
}
});
// ボタンを話した時のイベントをセット
pad.on('up', (buttonCode: number) => {
this.renderControllerButtonStatusText(buttonCode, false);
this.renderControllerButtonImage(buttonCode, false);
if (!this.isLStickControl) {
this.movePlayerWithCursor(buttonCode, false);
}
});
}
);
ちなみに、Phaser x Nintendo Switch Pro コントローラーのボタン操作において、1つ罠が存在します。
後述します。
Nintendo Switch Pro コントローラーのスティックの傾きを取得する
左スティックと右スティックの傾きは、Phaser.Input.Gamepad.Gamepad
のaxes
から取得できます。
> src/scenes/mainScene/mainScene.ts
Nintendo Switch Pro コントローラーの場合は…
-
pad.axes[0]
:左スティックのx方向 -
pad.axes[1]
:左スティックのy方向 -
pad.axes[2]
:右スティックのx方向 -
pad.axes[3]
:右スティックのy方向
で取得できました。
update() {
if (!this.pad) return;
// left stick
this.texts[0].text = `left stick axes x: ${this.pad.axes[0].getValue()}`;
this.texts[1].text = `left stick axes y: ${this.pad.axes[1].getValue()}`;
this.stickLButton.setPosition(
this.controllerBg.x +
this.controllerBg.width * -0.275 +
14 * this.pad.axes[0].getValue(),
this.controllerBg.y +
this.controllerBg.height * -0.195 +
14 * this.pad.axes[1].getValue()
);
// right stick
this.texts[2].text = `right stick axes x: ${this.pad.axes[2].getValue()}`;
this.texts[3].text = `right stick axes y: ${this.pad.axes[3].getValue()}`;
this.stickRButton.setPosition(
this.controllerBg.x +
this.controllerBg.width * 0.13 +
14 * this.pad.axes[2].getValue(),
this.controllerBg.y +
this.controllerBg.height * 0.002 +
14 * this.pad.axes[3].getValue()
);
}
Phaser x Nintendo Switch Pro コントローラーにおけるボタンコード対応表
以下は、Phaser x Nintendo Switch Pro コントローラーの組み合わせにおけるボタンコード対応表です。
ボタン | コード |
---|---|
B | 0 |
A | 1 |
Y | 2 |
X | 3 |
L | 4 |
R | 5 |
ZL | 6 |
ZR | 7 |
マイナス | 8 |
プラス | 9 |
左スティック | 10 |
右スティック | 11 |
十字カーソル ↑ | 12 |
十字カーソル ↓ | 13 |
十字カーソル ← | 14 |
十字カーソル → | 15 |
ホーム | 16 |
キャプチャ | 17 |
ボタンコードは、先述のpad: Phaser.Input.Gamepad.Gamepad
に対して、ボタン操作イベントを設定時のコールバック関数の引数から取得できます。
> src/scenes/mainScene/mainScene.ts
pad.on('down', (buttonCode: number) => {
// ↑コールバック関数の引数がボタンコードです
// 省略
});
注意点: Phaser x Nintendo Switch Pro コントローラーの罠
先ほど「Phaser x Nintendo Switch Pro コントローラーのボタン操作において、1つ罠が存在します。」と書いた点の詳細です。
実は Phaser において「どのボタンを押下したか」は、pad: Phaser.Input.Gamepad.Gamepad
から、pad.ボタン名
のカタチでも取得できます。
例えば、pad.L1
やpad.L2
、pad.R1
やpad.R2
…など。
pad.up
で十字カーソル↑、pad.down
で十字カーソル↓…などなど、いろいろ用意されています。
this.input.gamepad.once(
'connected',
(pad: Phaser.Input.Gamepad.Gamepad) => {
// button down
pad.on('down', () => {
console.log(pad.L1 ? "Lボタンを押下しました" : "Lボタン以外を押下しました")
});
}
);
しかし、本記事執筆時点のPhaser(v3.88.2)と、Nintendo Switch Pro コントローラーの組み合わせにおいて、pad.Aとpad.Bの実態が逆転します。
Aボタンを押下するとpad.Bがtrueとなり、Bボタンを押下するとpad.Aがtrueとなります。
原因は、よく分からないです…。
- Phaserの
Phaser.Input.Gamepad.Configs
を見てみると、DUALSHOCK_4
とXBOX_360
とSNES_USB
が定義されており、Nintendo Switch Pro コントローラーの定義はない。
単純にPhaser側でNintendo Switch Pro コントローラーが最適化されていないから? - 海外製のコントローラーと、日本製のコントローラーとでキー配置が異なるから?(本当に?)
- 私のPCが原因? MacOS Sequoiaなのですが、Windowsならうまくいく…とか?(本当に?)
…など、考えられる原因はいくつかあるのですが、ボタンのdown
とup
イベントのコールバック関数のボタンコードから、ちゃんと判定できるので「まぁ ヨシッ!」としました。
まとめ
以上、Nintendo Switch Pro コントローラーで、Phaserのブラウザゲームを操作する方法でした。
無事にコントローラーに接続できましたので、ちょっとゲームを作ってみようと思います。
Discussion