Files
next-portfolio/src/games/lib/control/Control.ts
2025-04-29 17:51:52 +01:00

88 lines
2.3 KiB
TypeScript

type state = 'down' | 'up';
// - TODO - Pull this from the actual game creating the controls
const GameControls = {
down: 'down',
up: 'up',
left: 'left',
right: 'right',
shift: 'shift',
' ': ' ',
} as const;
/**
* Abstraction for game controls, the game should say what controls it expects and then we can remap the actual controls separately.
* i.e. Both "ArrowDown" and "Down" from the keyboard listener should be the games "down" event.
* Also handles when the keys are pressed or not.
*/
class Control {
readonly gameControls = GameControls;
private _controlMap: { [key: string]: keyof typeof GameControls } = {
ArrowDown: GameControls.down,
Down: GameControls.down,
ArrowUp: GameControls.up,
Up: GameControls.up,
ArrowLeft: GameControls.left,
Left: GameControls.left,
ArrowRight: GameControls.right,
Right: GameControls.right,
Shift: GameControls.shift,
' ': GameControls[' '],
};
private _controlState: Map<keyof typeof GameControls, {
state: state,
consumed: boolean
}> = new Map();
constructor() {
this._setKeys();
window.addEventListener('keydown', (event) => {
if (this._controlState.get(this._controlMap[event.key])?.state !== 'down') {
this._controlState.set(this._controlMap[event.key], { state: 'down', consumed: false });
}
});
window.addEventListener('keyup', (event) => {
if (this._controlState.get(this._controlMap[event.key])?.state !== 'up') {
this._controlState.set(this._controlMap[event.key], { state: 'up', consumed: false });
}
});
}
/**
* - TODO
*/
private _setKeys(): void {
Object.keys(GameControls).forEach((key) => {
this._controlState.set(key as keyof typeof GameControls, { state: 'up', consumed: false });
});
}
/**
* - TODO
*
* @param key - TODO
*/
isDown(key: keyof typeof GameControls): boolean {
return this._controlState.get(key)?.state === 'down';
}
/**
* Consume a down key event once
*
* @param key - TODO
*/
onceDown(key: keyof typeof GameControls): boolean {
const keyState = this._controlState.get(key);
if (keyState && keyState.state === 'down' && !keyState.consumed) {
keyState.consumed = true;
return true;
}
return false;
}
}
export default Control;