import { Vector2D } from './Vector2D.js'; export class Input { constructor(canvas, viewport) { this.keys = new Set(); this.pressed = new Set(); this.mouse = new Vector2D(viewport.width / 2, viewport.height / 2); this.mouseDown = false; this.mouseClicked = false; this.viewport = viewport; this.isMobile = 'ontouchstart' in window || navigator.maxTouchPoints > 0; this.joystickActive = false; this.joystickTouchId = null; this.joystickBasePos = { x: 0, y: 0 }; this.joystickRadius = 60; window.addEventListener('keydown', (event) => { this.keys.add(event.key.toLowerCase()); if (!event.repeat) { this.pressed.add(event.key.toLowerCase()); } if (event.key === ' ') { event.preventDefault(); if ( document.activeElement && document.activeElement.tagName === 'BUTTON' && typeof document.activeElement.blur === 'function' ) { document.activeElement.blur(); } } }); window.addEventListener('keyup', (event) => { this.keys.delete(event.key.toLowerCase()); }); window.addEventListener('blur', () => { this.keys.clear(); this.pressed.clear(); this.mouseDown = false; }); canvas.addEventListener('mousemove', (event) => { const rect = canvas.getBoundingClientRect(); this.mouse.x = ((event.clientX - rect.left) / rect.width) * viewport.width; this.mouse.y = ((event.clientY - rect.top) / rect.height) * viewport.height; }); canvas.addEventListener('mousedown', (event) => { if (event.button === 0) { this.mouseDown = true; this.mouseClicked = true; } }); window.addEventListener('mouseup', () => { this.mouseDown = false; }); if (this.isMobile) { this._initTouchJoystick(canvas); } } _initTouchJoystick(canvas) { this.joystickBaseEl = document.createElement('div'); this.joystickBaseEl.className = 'joystick-base'; this.joystickBaseEl.style.display = 'none'; this.joystickThumbEl = document.createElement('div'); this.joystickThumbEl.className = 'joystick-thumb'; this.joystickThumbEl.style.display = 'none'; document.body.appendChild(this.joystickBaseEl); document.body.appendChild(this.joystickThumbEl); canvas.addEventListener('touchstart', (event) => this._handleTouchStart(event), { passive: false }); canvas.addEventListener('touchmove', (event) => this._handleTouchMove(event), { passive: false }); canvas.addEventListener('touchend', (event) => this._handleTouchEnd(event), { passive: false }); canvas.addEventListener('touchcancel', (event) => this._handleTouchEnd(event), { passive: false }); } _handleTouchStart(event) { event.preventDefault(); for (const touch of event.changedTouches) { const x = touch.clientX; if (x < this.viewport.width / 2 && !this.joystickActive) { this.joystickActive = true; this.joystickTouchId = touch.identifier; this.joystickBasePos.x = x; this.joystickBasePos.y = touch.clientY; this.joystickBaseEl.style.left = `${x}px`; this.joystickBaseEl.style.top = `${this.joystickBasePos.y}px`; this.joystickBaseEl.style.display = 'block'; this.joystickThumbEl.style.left = `${x}px`; this.joystickThumbEl.style.top = `${this.joystickBasePos.y}px`; this.joystickThumbEl.style.display = 'block'; } } } _handleTouchMove(event) { event.preventDefault(); for (const touch of event.changedTouches) { if (touch.identifier !== this.joystickTouchId) continue; const dx = touch.clientX - this.joystickBasePos.x; const dy = touch.clientY - this.joystickBasePos.y; const dist = Math.sqrt(dx * dx + dy * dy); let clampedDx = dx; let clampedDy = dy; if (dist > this.joystickRadius) { clampedDx = (dx / dist) * this.joystickRadius; clampedDy = (dy / dist) * this.joystickRadius; } this.joystickThumbEl.style.left = `${this.joystickBasePos.x + clampedDx}px`; this.joystickThumbEl.style.top = `${this.joystickBasePos.y + clampedDy}px`; const deadZone = 12; this.keys.delete('w'); this.keys.delete('a'); this.keys.delete('s'); this.keys.delete('d'); if (dy < -deadZone) this.keys.add('w'); if (dy > deadZone) this.keys.add('s'); if (dx < -deadZone) this.keys.add('a'); if (dx > deadZone) this.keys.add('d'); } } _handleTouchEnd(event) { for (const touch of event.changedTouches) { if (touch.identifier === this.joystickTouchId) { this.joystickActive = false; this.joystickTouchId = null; this.keys.delete('w'); this.keys.delete('a'); this.keys.delete('s'); this.keys.delete('d'); this.joystickBaseEl.style.display = 'none'; this.joystickThumbEl.style.display = 'none'; } } } clearPressed() { this.pressed.clear(); this.mouseClicked = false; } }