UNPKG

ridder

Version:

A straightforward game engine for simple data-driven games in JavaScript

170 lines (169 loc) 4.77 kB
import { getCameraPosition } from "./camera.js"; import { canvas, scale } from "./canvas.js"; import { InputCode } from "./consts.js"; import { vec } from "./vector.js"; const inputsDown = {}; const inputsPressed = {}; const inputsReleased = {}; const mousePosition = vec(); const mousePositionInWorld = vec(); /** * Add the event listeners to listen to key and mouse events. */ export function setupInput() { window.addEventListener("keydown", (event) => { event.preventDefault(); onDown(event.code); }); window.addEventListener("keyup", (event) => { event.preventDefault(); onUp(event.code); }); canvas.addEventListener("pointerdown", (event) => { event.preventDefault(); onPointerEvent(event); const code = getMouseButtonCode(event.button); if (code) { onDown(code); } }); canvas.addEventListener("pointerup", (event) => { event.preventDefault(); onPointerEvent(event); const code = getMouseButtonCode(event.button); if (code) { onUp(code); } }); canvas.addEventListener("pointermove", (event) => { event.preventDefault(); onPointerEvent(event); }); // Disable context menu to enable right mouse button as input. canvas.addEventListener("contextmenu", (event) => { event.preventDefault(); }); // Prevent sticky keys when the window loses focus or is minimized. window.addEventListener("focus", resetInputs); window.addEventListener("blur", resetInputs); document.addEventListener("visibilitychange", resetInputs); } /** * Handle key or mouse down event. */ function onDown(code) { if (inputsDown[code]) return; inputsDown[code] = true; inputsPressed[code] = true; inputsReleased[code] = false; } /** * Handle key or mouse up event. */ function onUp(code) { inputsDown[code] = false; inputsPressed[code] = false; inputsReleased[code] = true; } /** * Handle generic pointer event. */ function onPointerEvent(event) { mousePosition.x = event.clientX / scale.x; mousePosition.y = event.clientY / scale.y; const camera = getCameraPosition(); mousePositionInWorld.x = mousePosition.x + camera.x; mousePositionInWorld.y = mousePosition.y + camera.y; } /** * Translate the numerical mouse button to a string, similar to the key codes. */ function getMouseButtonCode(button) { switch (button) { case 0: return InputCode.MOUSE_LEFT; case 1: return InputCode.MOUSE_MIDDLE; case 2: return InputCode.MOUSE_RIGHT; default: return null; } } /** * Reset a single input's state back to `false`. */ export function resetInput(code) { inputsDown[code] = false; inputsPressed[code] = false; inputsReleased[code] = false; } /** * Reset the pressed and released inputs back to `false`. */ export function resetInputs() { for (const key in inputsPressed) { inputsPressed[key] = false; } for (const key in inputsReleased) { inputsReleased[key] = false; } } /** * Reset all inputs back to `false`. */ export function resetAllInputs() { for (const key in inputsDown) { inputsDown[key] = false; } for (const key in inputsPressed) { inputsPressed[key] = false; } for (const key in inputsReleased) { inputsReleased[key] = false; } } /** * Returns `true` if the input is currently pressed. * * Optionally consumes the input so that sequential calls in the current frame return `false`. */ export function isInputPressed(code, consume = false) { const isPressed = !!inputsPressed[code]; if (isPressed && consume) { inputsDown[code] = false; inputsPressed[code] = false; } return isPressed; } /** * Returns `true` if the input is currently down. * * Optionally consumes the input so that sequential calls in the current frame return `false`. */ export function isInputDown(code, consume = false) { const isDown = !!inputsDown[code]; if (isDown && consume) { inputsDown[code] = false; inputsPressed[code] = false; } return isDown; } /** * Returns `true` if the input is currently released. */ export function isInputReleased(code, consume = false) { const isReleased = !!inputsReleased[code]; if (isReleased && consume) { inputsReleased[code] = false; } return isReleased; } /** * Get the current mouse position on the canvas. * @param inWorld Whether or not to get the mouse position affected by the camera. */ export function getMousePosition(inWorld) { return inWorld ? mousePositionInWorld : mousePosition; }