Spaces:
Running
Running
Codex CLI
feat(player): enhance movement mechanics with sliding, jump buffering, and wall bounce features
d6dfcf1
| import { G } from './globals.js'; | |
| import { CFG } from './config.js'; | |
| import { showOverlay } from './hud.js'; | |
| import { initAudio, resumeAudio } from './audio.js'; | |
| import { primeGrenade, releaseGrenade } from './grenades.js'; | |
| export function setupEvents({ startGame, restartGame, beginReload, updateWeaponAnchor }) { | |
| const overlay = document.getElementById('overlay'); | |
| if (!overlay) return; | |
| overlay.addEventListener('click', () => { | |
| // Initialize audio on user gesture | |
| initAudio(); | |
| if (G.state === 'menu') { | |
| G.controls.lock(); | |
| } else if (G.state === 'paused') { | |
| G.controls.lock(); | |
| } else if (G.state === 'gameover') { | |
| // Restart on click after game over | |
| restartGame(); | |
| } | |
| }); | |
| G.controls.addEventListener('lock', () => { | |
| if (G.state === 'menu') { | |
| startGame(); | |
| } else if (G.state === 'paused') { | |
| G.state = 'playing'; | |
| overlay.classList.add('hidden'); | |
| } else if (G.state === 'gameover') { | |
| // Treat lock like a fresh start after game over | |
| startGame(); | |
| } | |
| }); | |
| G.controls.addEventListener('unlock', () => { | |
| if (G.state === 'playing') { | |
| G.state = 'paused'; | |
| showOverlay('paused'); | |
| } | |
| }); | |
| document.addEventListener('keydown', (e) => { | |
| switch (e.code) { | |
| case 'KeyW': G.input.w = true; break; | |
| case 'KeyA': G.input.a = true; break; | |
| case 'KeyS': G.input.s = true; break; | |
| case 'KeyD': G.input.d = true; break; | |
| case 'ShiftLeft': G.input.sprint = true; break; | |
| case 'KeyC': G.input.crouch = true; break; | |
| case 'KeyG': | |
| if (G.state === 'playing') { | |
| G.input.grenade = true; | |
| primeGrenade(); | |
| } | |
| break; | |
| case 'Space': | |
| if (G.state === 'playing') { | |
| // Use buffered jump handled in player physics | |
| G.input.jump = true; | |
| } | |
| break; | |
| case 'KeyF': | |
| if (G.state === 'playing' && G.flashlight) { | |
| G.flashlight.visible = !G.flashlight.visible; | |
| } | |
| break; | |
| case 'KeyP': | |
| case 'Escape': | |
| if (G.state === 'playing') { | |
| G.controls.unlock(); | |
| } | |
| break; | |
| case 'KeyR': | |
| if (G.state === 'playing') { | |
| beginReload(); | |
| } | |
| break; | |
| } | |
| }); | |
| document.addEventListener('keyup', (e) => { | |
| switch (e.code) { | |
| case 'KeyW': G.input.w = false; break; | |
| case 'KeyA': G.input.a = false; break; | |
| case 'KeyS': G.input.s = false; break; | |
| case 'KeyD': G.input.d = false; break; | |
| case 'ShiftLeft': G.input.sprint = false; break; | |
| case 'KeyC': G.input.crouch = false; break; | |
| case 'KeyG': | |
| if (G.input.grenade) { | |
| G.input.grenade = false; | |
| releaseGrenade(); | |
| } | |
| break; | |
| case 'Space': | |
| G.input.jump = false; | |
| break; | |
| } | |
| }); | |
| document.addEventListener('mousedown', (e) => { | |
| if (e.button === 0 && G.state === 'playing') { | |
| // Ensure audio context is running on interaction | |
| resumeAudio(); | |
| G.input.shoot = true; | |
| } | |
| }); | |
| document.addEventListener('mouseup', (e) => { | |
| if (e.button === 0) { | |
| G.input.shoot = false; | |
| } | |
| }); | |
| window.addEventListener('resize', () => { | |
| G.camera.aspect = window.innerWidth / window.innerHeight; | |
| G.camera.updateProjectionMatrix(); | |
| G.renderer.setSize(window.innerWidth, window.innerHeight); | |
| updateWeaponAnchor(); | |
| }); | |
| } | |