【Gamepad API】Logicoolゲームパッドの操作イベントをJSで取得する
概要
Logicoolのゲームパッドを買ったので、コントローラーで操作できるWebの何かを作ろうと思い
JavaScriptでボタンのイベント取得する方法を備忘録としてまとめます。
動作環境
- Mac(ブラウザ: Google Chrome)
- Logicool ゲームパッド( https://www.amazon.co.jp/dp/B00CDG799E )
LogicoolをMacで動かす
LogicoolはWindows向けのゲームパッドですが、ドライバーを入れればMacでも動作しました。
↓ドライバーの入れ方はこちらを参考にさせていただきました。
ドライバーを正常にインストールできると画像のようにシステム環境設定にゲームパッドのメニューが表示されます。
開くとこのような感じでゲームパッドの動作テスト等できる画面になります。
ゲームパッドのボタンを適当に押してみて、この画面でシミュレーションができれば正常にMacに接続されていることがわかります。
接続イベント
ボタン押下イベントの取得の前にまずゲームパッドが接続されているかを取得する必要があります。
gamepadconnectedイベントを利用して取得してみます。
window.addEventListener("gamepadconnected", (e) => {
console.log(
"Gamepad connected at index %d: %s. %d buttons, %d axes.",
e.gamepad.index,
e.gamepad.id,
e.gamepad.buttons.length,
e.gamepad.axes.length
);
});
接続が確認できた場合はコンソールにこのように表示されます。
Gamepad connected at index 0: Xbox 360 Wired Controller (Vendor: 046d Product: c21d). 15 buttons, 6 axes.
この接続確認ができてからボタンの取得などを行います。
ボタン押下の取得
ボタン押下に関しては特にイベントが用意されていなさそうなのでrequestAnimationFrame
で毎フレーム確認しに行く方法で実装します。
const buttonPressed = (button) => {
if (typeof button == "object") {
return button.pressed;
}
return button == 1.0;
};
const gameLoop = () => {
const gamepads = navigator.getGamepads
? navigator.getGamepads()
: navigator.webkitGetGamepads
? navigator.webkitGetGamepads
: [];
if (!gamepads) {
return;
}
const gp = gamepads[0];
if (buttonPressed(gp.buttons[0])) {
console.log("Aボタン押下")
};
requestAnimationFrame(gameLoop);
};
MDNのドキュメントを参考にしています。
ここではシンプルにAボタンを押下時にコンソールへメッセージを表示するようにしています。
(このgameLoop関数は先ほどのwindow.addEventListener("gamepadconnected", ...
の中で呼びます)
ボタンの対応表
ボタンはgamepads.buttons
、アナログスティック系(次章)はgamepads.axes
でそれぞれのArrayが取得できます。
Gamepad APIのドキュメントにはXBox 360公式ゲームパッドのボタンレイアウトが掲載されていました。
buttons: [
'DPad-Up','DPad-Down','DPad-Left','DPad-Right',
'Start','Back','Axis-Left','Axis-Right',
'LB','RB','Power','A','B','X','Y',
],
ただ、今回使うLogicoolのゲームパッドは異なりましたので以下にまとめています。(他のゲームパッドはまた異なると思いますのでご注意ください)
試してみると左側のアナログスティックがボタンだったり、スティック側に十字キーが入ってたりもしますが…この辺は安価の非公式のゲームパッドなのでしょうがないですね。
Logicoolボタン | 配列番号 |
---|---|
A | 0 |
B | 1 |
X | 2 |
Y | 3 |
LB | 4 |
RB | 5 |
左スティック押し込み | 6 |
右スティック押し込み | 7 |
START | 8 |
BACK | 9 |
中央Logicoolボタン | 10 |
左スティック上 | 11 |
左スティック下 | 12 |
左スティック左 | 13 |
左スティック右 | 14 |
スティックの入力取得
booleanを返すボタンに対して、スティック(LT, RT含む)は-1〜1の値を返します。
Logicoolスティック | 配列番号 | 値 |
---|---|---|
十字キー左 | 0 | -1 |
十字キー右 | 0 | 1 |
十字キー上 | 1 | -1 |
十字キー下 | 1 | 1 |
LT | 2 | 1 |
右スティック左 | 3 | -1 |
右スティック右 | 3 | 1 |
右スティック上 | 4 | -1 |
右スティック下 | 4 | 1 |
RT | 5 | 1 |
操作デモ
今回はボタンの入力を取得して画像が動くデモを作ってみます。
<head>
<style>
body {
margin: 0;
background: black;
}
.kuma {
position: fixed;
top: calc(50% - 50px);
left: calc(50% - 50px);
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<img id="kuma" class="kuma" src="kuma.gif" />
<script>
const kuma = document.getElementById("kuma");
let start;
let a = 0;
let b = 0;
const buttonPressed = (button) => {
if (typeof button == "object") {
return button.pressed;
}
return button == 1.0;
};
const gameLoop = () => {
const gamepads = navigator.getGamepads
? navigator.getGamepads()
: navigator.webkitGetGamepads
? navigator.webkitGetGamepads
: [];
if (!gamepads) {
return;
}
const gp = gamepads[0];
if (buttonPressed(gp.buttons[3])) {
b--;
} else if (buttonPressed(gp.buttons[0])) {
b++;
}
if (buttonPressed(gp.buttons[1])) {
a++;
} else if (buttonPressed(gp.buttons[2])) {
a--;
}
const kumaLeft = kuma.getBoundingClientRect().left;
const kumaTop = kuma.getBoundingClientRect().top;
const speed = 5;
kuma.style.left = kumaLeft + a * speed + "px";
kuma.style.top = kumaTop + b * speed + "px";
a = 0;
b = 0;
start = requestAnimationFrame(gameLoop);
};
window.addEventListener("gamepadconnected", (e) => {
gameLoop();
});
</script>
</body>
無事動かすことができました。
参考
Discussion