mirror of
https://github.com/Terncode/pixel.horse.git
synced 2026-09-25 22:25:53 +02:00
171 lines
4.3 KiB
TypeScript
171 lines
4.3 KiB
TypeScript
import { clamp } from 'lodash';
|
|
import { KeyboardController } from './keyboard';
|
|
import { MouseController } from './mouse';
|
|
import { TouchController } from './touch';
|
|
import { GamePadController } from './gamepad';
|
|
import { InputController, Key } from './input';
|
|
import { array, times } from '../../common/utils';
|
|
|
|
type Handler = (input: Key, value: number) => boolean | void;
|
|
|
|
const KEYS = Key.MAX_VALUE;
|
|
|
|
export class InputManager {
|
|
disabledGamepad = false;
|
|
disabledKeyboard = false;
|
|
disableArrows = false;
|
|
usingTouch = false;
|
|
private state: number[];
|
|
private prevState: number[];
|
|
private actions: Handler[][];
|
|
private controllers: InputController[] = [];
|
|
constructor() {
|
|
this.state = array(KEYS, 0);
|
|
this.prevState = array(KEYS, 0);
|
|
this.actions = times(KEYS, () => []);
|
|
}
|
|
get axisX() {
|
|
const axisX = this.getRange(Key.GAMEPAD_AXIS1_X);
|
|
const left = this.disableArrows ? this.getState(Key.KEY_A) : this.getState(Key.LEFT, Key.KEY_A);
|
|
const right = this.disableArrows ? this.getState(Key.KEY_D) : this.getState(Key.RIGHT, Key.KEY_D);
|
|
const x = axisX + (left ? -1 : (right ? 1 : 0));
|
|
return clamp(x, -1, 1);
|
|
}
|
|
get axisY() {
|
|
const axisY = this.getRange(Key.GAMEPAD_AXIS1_Y);
|
|
const up = this.disableArrows ? this.getState(Key.KEY_W) : this.getState(Key.UP, Key.KEY_W);
|
|
const down = this.disableArrows ? this.getState(Key.KEY_S) : this.getState(Key.DOWN, Key.KEY_S);
|
|
const y = axisY + (up ? -1 : (down ? 1 : 0));
|
|
return clamp(y, -1, 1);
|
|
}
|
|
get isMovementFromButtons() {
|
|
const up = this.getState(Key.UP, Key.KEY_W);
|
|
const down = this.getState(Key.DOWN, Key.KEY_S);
|
|
const left = this.getState(Key.LEFT, Key.KEY_A);
|
|
const right = this.getState(Key.RIGHT, Key.KEY_D);
|
|
return up || down || left || right;
|
|
}
|
|
get axis2X() {
|
|
return clamp(this.getRange(Key.GAMEPAD_AXIS2_X), -1, 1);
|
|
}
|
|
get axis2Y() {
|
|
return clamp(this.getRange(Key.GAMEPAD_AXIS2_Y), -1, 1);
|
|
}
|
|
get pointerX() {
|
|
return this.getRange(Key.MOUSE_X);
|
|
}
|
|
get pointerY() {
|
|
return this.getRange(Key.MOUSE_Y);
|
|
}
|
|
get wheelX() {
|
|
return this.getRange(Key.MOUSE_WHEEL_X);
|
|
}
|
|
get wheelY() {
|
|
return this.getRange(Key.MOUSE_WHEEL_Y);
|
|
}
|
|
initialize(element: HTMLElement) {
|
|
this.controllers = [
|
|
new KeyboardController(this),
|
|
new MouseController(this),
|
|
new TouchController(this),
|
|
new GamePadController(this),
|
|
];
|
|
|
|
this.controllers.forEach(c => c.initialize(element));
|
|
this.clear();
|
|
}
|
|
release() {
|
|
this.controllers.forEach(c => c.release());
|
|
this.controllers = [];
|
|
this.clear();
|
|
}
|
|
update() {
|
|
for (const controller of this.controllers) {
|
|
controller.update();
|
|
}
|
|
}
|
|
end() {
|
|
for (let i = 0; i < KEYS; i++) {
|
|
this.prevState[i] = this.state[i];
|
|
}
|
|
|
|
this.setValue(Key.TOUCH_CLICK, 0);
|
|
this.setValue(Key.TOUCH_SECOND_CLICK, 0);
|
|
this.setValue(Key.MOUSE_WHEEL_X, 0);
|
|
this.setValue(Key.MOUSE_WHEEL_Y, 0);
|
|
}
|
|
clear() {
|
|
for (let i = 0; i < KEYS; i++) {
|
|
this.state[i] = 0;
|
|
this.prevState[i] = 0;
|
|
}
|
|
|
|
for (const controller of this.controllers) {
|
|
controller.clear();
|
|
}
|
|
}
|
|
onPressed(inputs: Key[] | Key, handler: () => void) {
|
|
this.onAction(inputs, (_, v) => {
|
|
if (v === 1) {
|
|
handler();
|
|
}
|
|
});
|
|
}
|
|
onReleased(inputs: Key[] | Key, handler: () => void) {
|
|
this.onAction(inputs, (_, v) => {
|
|
if (v === 0) {
|
|
handler();
|
|
}
|
|
});
|
|
}
|
|
isPressed(key: Key) {
|
|
return this.state[key] !== 0;
|
|
}
|
|
wasPressed(key: Key): boolean {
|
|
return this.state[key] === 1 && this.prevState[key] === 0;
|
|
}
|
|
private onAction(inputs: Key[] | Key, handler: Handler) {
|
|
const inputsArray = Array.isArray(inputs) ? inputs : [inputs];
|
|
|
|
for (const i of inputsArray) {
|
|
this.actions[i].push(handler);
|
|
}
|
|
}
|
|
private getState(...inputs: Key[]): boolean {
|
|
for (const i of inputs) {
|
|
if (this.state[i] !== 0) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
private getRange(input: Key): number {
|
|
return this.state[input];
|
|
}
|
|
setValue(input: Key, value: number): boolean {
|
|
if (input < 0 || input >= KEYS) {
|
|
console.warn(`Input out of range: ${input}`);
|
|
} else if (this.state[input] !== value) {
|
|
this.state[input] = value;
|
|
|
|
if (this.actions[input] && this.actions[input].length) {
|
|
for (const action of this.actions[input]) {
|
|
action(input, value);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
addValue(input: Key, value: number) {
|
|
if (input < 0 || input >= KEYS) {
|
|
console.warn(`Input out of range: ${input}`);
|
|
} else {
|
|
this.state[input] += value;
|
|
}
|
|
}
|
|
}
|