add SnesInput class to represent controller input
separate input handling (from keyboard and gamepad) from the results thereof
This commit is contained in:
parent
e13c4d0985
commit
02c1907d26
176
main.js
176
main.js
@ -12,7 +12,7 @@ function bound(low, x, high) {
|
||||
return Math.max(low, Math.min(x, high));
|
||||
}
|
||||
|
||||
class Input {
|
||||
class SnesInput {
|
||||
constructor() {
|
||||
this.up = false;
|
||||
this.down = false;
|
||||
@ -26,72 +26,21 @@ class Input {
|
||||
this.r = false;
|
||||
this.select = false;
|
||||
this.start = false;
|
||||
|
||||
this.keysPressed = {};
|
||||
|
||||
window.addEventListener('gamepadconnected', this.gamepadConnected);
|
||||
window.addEventListener('gamepaddisconnected', this.gamepadDisconnected);
|
||||
document.addEventListener('keydown', (e) => this.keyDown(e));
|
||||
document.addEventListener('keyup', (e) => this.keyUp(e));
|
||||
}
|
||||
|
||||
keyDown(e) {
|
||||
this.keysPressed[e.key] = true;
|
||||
}
|
||||
|
||||
keyUp(e) {
|
||||
this.keysPressed[e.key] = false;
|
||||
}
|
||||
|
||||
update() {
|
||||
// Default ZSNES keybindings. See:
|
||||
// http://zsnes-docs.sourceforge.net/html/readme.htm#default_keys
|
||||
this.up = this.keysPressed['ArrowUp'];
|
||||
this.down = this.keysPressed['ArrowDown'];
|
||||
this.left = this.keysPressed['ArrowLeft'];
|
||||
this.right = this.keysPressed['ArrowRight'];
|
||||
this.start = this.keysPressed['Enter'];
|
||||
this.select = this.keysPressed['Shift'];
|
||||
this.a = this.keysPressed['x'];
|
||||
this.b = this.keysPressed['z'];
|
||||
this.x = this.keysPressed['s'];
|
||||
this.y = this.keysPressed['a'];
|
||||
this.l = this.keysPressed['d'];
|
||||
this.r = this.keysPressed['c'];
|
||||
|
||||
const gamepad = navigator.getGamepads()[0];
|
||||
if (gamepad == null || !gamepad.connected || gamepad.axes.length < 2 ||
|
||||
gamepad.buttons.length < 12) {
|
||||
return;
|
||||
}
|
||||
// TODO: have a config screen instead of hard-coding the 8Bitdo SNES30 pad.
|
||||
// TODO: handle connects / disconnects more correctly.
|
||||
this.up |= gamepad.axes[1] < 0;
|
||||
this.down |= gamepad.axes[1] > 0;
|
||||
this.left |= gamepad.axes[0] < 0;
|
||||
this.right |= gamepad.axes[0] > 0;
|
||||
this.a |= gamepad.buttons[0].pressed;
|
||||
this.b |= gamepad.buttons[1].pressed;
|
||||
this.x |= gamepad.buttons[3].pressed;
|
||||
this.y |= gamepad.buttons[4].pressed;
|
||||
this.l |= gamepad.buttons[6].pressed;
|
||||
this.r |= gamepad.buttons[7].pressed;
|
||||
this.select |= gamepad.buttons[10].pressed;
|
||||
this.start |= gamepad.buttons[11].pressed;
|
||||
debug(this.toString());
|
||||
}
|
||||
|
||||
gamepadConnected(e) {
|
||||
debug('gamepad connected! :)');
|
||||
console.log('gamepad connected @ index %d: %d buttons, %d axes\n[%s]',
|
||||
e.gamepad.index, e.gamepad.buttons.length, e.gamepad.axes.length,
|
||||
e.gamepad.id);
|
||||
}
|
||||
|
||||
gamepadDisconnected(e) {
|
||||
debug('gamepad disconnected :(');
|
||||
console.log('gamepad disconnected @ index %d:\n[%s]', e.gamepad.index,
|
||||
e.gamepad.id);
|
||||
copyFrom(other) {
|
||||
this.up = other.up;
|
||||
this.down = other.down;
|
||||
this.left = other.left;
|
||||
this.right = other.right;
|
||||
this.a = other.a;
|
||||
this.b = other.b;
|
||||
this.x = other.x;
|
||||
this.y = other.y;
|
||||
this.l = other.l;
|
||||
this.r = other.r;
|
||||
this.select = other.select;
|
||||
this.start = other.start;
|
||||
}
|
||||
|
||||
toString() {
|
||||
@ -143,6 +92,89 @@ class Input {
|
||||
}
|
||||
}
|
||||
|
||||
class InputHandler {
|
||||
constructor() {
|
||||
this.up = false;
|
||||
this.down = false;
|
||||
this.left = false;
|
||||
this.right = false;
|
||||
this.a = false;
|
||||
this.b = false;
|
||||
this.x = false;
|
||||
this.y = false;
|
||||
this.l = false;
|
||||
this.r = false;
|
||||
this.select = false;
|
||||
this.start = false;
|
||||
|
||||
this.keysPressed = {};
|
||||
|
||||
window.addEventListener('gamepadconnected', this.gamepadConnected);
|
||||
window.addEventListener('gamepaddisconnected', this.gamepadDisconnected);
|
||||
document.addEventListener('keydown', (e) => this.keyDown(e));
|
||||
document.addEventListener('keyup', (e) => this.keyUp(e));
|
||||
}
|
||||
|
||||
keyDown(e) {
|
||||
this.keysPressed[e.key] = true;
|
||||
}
|
||||
|
||||
keyUp(e) {
|
||||
this.keysPressed[e.key] = false;
|
||||
}
|
||||
|
||||
update(input) {
|
||||
// Default ZSNES keybindings. See:
|
||||
// http://zsnes-docs.sourceforge.net/html/readme.htm#default_keys
|
||||
input.up = this.keysPressed['ArrowUp'];
|
||||
input.down = this.keysPressed['ArrowDown'];
|
||||
input.left = this.keysPressed['ArrowLeft'];
|
||||
input.right = this.keysPressed['ArrowRight'];
|
||||
input.start = this.keysPressed['Enter'];
|
||||
input.select = this.keysPressed['Shift'];
|
||||
input.a = this.keysPressed['x'];
|
||||
input.b = this.keysPressed['z'];
|
||||
input.x = this.keysPressed['s'];
|
||||
input.y = this.keysPressed['a'];
|
||||
input.l = this.keysPressed['d'];
|
||||
input.r = this.keysPressed['c'];
|
||||
|
||||
const gamepad = navigator.getGamepads()[0];
|
||||
if (gamepad == null || !gamepad.connected || gamepad.axes.length < 2 ||
|
||||
gamepad.buttons.length < 12) {
|
||||
return;
|
||||
}
|
||||
// TODO: have a config screen instead of hard-coding the 8Bitdo SNES30 pad.
|
||||
// TODO: handle connects / disconnects more correctly.
|
||||
input.up |= gamepad.axes[1] < 0;
|
||||
input.down |= gamepad.axes[1] > 0;
|
||||
input.left |= gamepad.axes[0] < 0;
|
||||
input.right |= gamepad.axes[0] > 0;
|
||||
input.a |= gamepad.buttons[0].pressed;
|
||||
input.b |= gamepad.buttons[1].pressed;
|
||||
input.x |= gamepad.buttons[3].pressed;
|
||||
input.y |= gamepad.buttons[4].pressed;
|
||||
input.l |= gamepad.buttons[6].pressed;
|
||||
input.r |= gamepad.buttons[7].pressed;
|
||||
input.select |= gamepad.buttons[10].pressed;
|
||||
input.start |= gamepad.buttons[11].pressed;
|
||||
debug(input.toString());
|
||||
}
|
||||
|
||||
gamepadConnected(e) {
|
||||
debug('gamepad connected! :)');
|
||||
console.log('gamepad connected @ index %d: %d buttons, %d axes\n[%s]',
|
||||
e.gamepad.index, e.gamepad.buttons.length, e.gamepad.axes.length,
|
||||
e.gamepad.id);
|
||||
}
|
||||
|
||||
gamepadDisconnected(e) {
|
||||
debug('gamepad disconnected :(');
|
||||
console.log('gamepad disconnected @ index %d:\n[%s]', e.gamepad.index,
|
||||
e.gamepad.id);
|
||||
}
|
||||
}
|
||||
|
||||
class Graphics {
|
||||
constructor(canvas) {
|
||||
this.canvas_ = canvas;
|
||||
@ -223,7 +255,9 @@ class World {
|
||||
constructor() {
|
||||
this.state_ = null;
|
||||
this.fpsCounter_ = new FpsCounter();
|
||||
this.input_ = new Input();
|
||||
this.inputHandler_ = new InputHandler();
|
||||
this.input_ = new SnesInput();
|
||||
this.lastInput_ = new SnesInput();
|
||||
this.player_ = new Player();
|
||||
|
||||
// TODO: move rendering stuff to a separate object.
|
||||
@ -235,9 +269,13 @@ class World {
|
||||
|
||||
update(timestampMs) {
|
||||
this.fpsCounter_.update(timestampMs);
|
||||
const wasRPressed = this.input_.r;
|
||||
this.input_.update();
|
||||
if (!wasRPressed && this.input_.r) {
|
||||
|
||||
// We copy values to avoid allocating new SnesInput objects every frame.
|
||||
// TODO: is this actually worth it?
|
||||
this.lastInput_.copyFrom(this.input_);
|
||||
this.inputHandler_.update(this.input_);
|
||||
|
||||
if (!this.lastInput_.r && this.input_.r) {
|
||||
this.player_.cycleSprite();
|
||||
}
|
||||
if (this.input_.left) {
|
||||
|
Loading…
Reference in New Issue
Block a user