/** * DOOM 3D - Master Game Manager & Application Entry Point * Orchestrates loop, state transitions, settings, audio sync, and rendering. */ class DoomGame { constructor() { this.container = document.getElementById('game-container'); this.state = 'start'; // 'start', 'playing', 'paused', 'gameover' this.sound = new SoundSystem(); this.engine = new DoomEngine(this.container); this.map = new DoomMap(this.engine, this.sound); this.player = new DoomPlayer(this.engine, this.sound); this.weapons = new DoomWeapons(this.engine, this.player, this.sound); this.enemies = new DoomEnemies(this.engine, this.player, this.sound, this.map); this.items = new DoomItems(this.engine, this.player, this.sound, this.map); this.hud = new DoomHUD(this.player); this.mobile = new DoomMobileControls(this.player); this.lastTime = performance.now(); this.crtFilterEnabled = true; this.setupUI(); this.loop = this.loop.bind(this); requestAnimationFrame(this.loop); } setupUI() { // Start Game Button const startBtn = document.getElementById('btn-start-game'); if (startBtn) { startBtn.addEventListener('click', () => { this.startGame(); }); } // Restart Game Button const restartBtn = document.getElementById('btn-restart'); if (restartBtn) { restartBtn.addEventListener('click', () => { this.restartGame(); }); } // Pause Menu Resume Button const resumeBtn = document.getElementById('btn-resume'); if (resumeBtn) { resumeBtn.addEventListener('click', () => { this.resumeGame(); }); } // Settings Modal Open/Close const settingsBtn = document.getElementById('btn-settings'); const settingsModal = document.getElementById('settings-modal'); const closeSettingsBtn = document.getElementById('btn-close-settings'); if (settingsBtn && settingsModal) { settingsBtn.addEventListener('click', () => { settingsModal.classList.remove('hidden'); }); } if (closeSettingsBtn && settingsModal) { closeSettingsBtn.addEventListener('click', () => { settingsModal.classList.add('hidden'); }); } // Settings Sliders const sfxSlider = document.getElementById('slider-sfx'); const musicSlider = document.getElementById('slider-music'); const sensSlider = document.getElementById('slider-sens'); const crtCheck = document.getElementById('toggle-crt'); if (sfxSlider) { sfxSlider.addEventListener('input', (e) => { this.sound.setSfxVolume(parseFloat(e.target.value)); }); } if (musicSlider) { musicSlider.addEventListener('input', (e) => { this.sound.setMusicVolume(parseFloat(e.target.value)); }); } if (sensSlider) { sensSlider.addEventListener('input', (e) => { this.player.mouseSensitivity = parseFloat(e.target.value) * 0.002; }); } if (crtCheck) { crtCheck.addEventListener('change', (e) => { this.toggleCRTFilter(e.target.checked); }); } // ESC key to toggle pause window.addEventListener('keydown', (e) => { if (e.code === 'Escape') { if (this.state === 'playing') { this.pauseGame(); } else if (this.state === 'paused') { this.resumeGame(); } } }); } startGame() { this.state = 'playing'; const startOverlay = document.getElementById('start-screen'); if (startOverlay) startOverlay.classList.add('hidden'); this.sound.init(); this.player.requestPointerLock(); this.hud.showNotification('ENTER THE TECH BASE. RIP AND TEAR!'); } pauseGame() { this.state = 'paused'; this.player.exitPointerLock(); const pauseOverlay = document.getElementById('pause-menu'); if (pauseOverlay) pauseOverlay.classList.remove('hidden'); } resumeGame() { this.state = 'playing'; const pauseOverlay = document.getElementById('pause-menu'); if (pauseOverlay) pauseOverlay.classList.add('hidden'); this.player.requestPointerLock(); } restartGame() { this.hud.hideGameOver(); this.player.respawn(this.map.spawns.player); this.state = 'playing'; this.player.requestPointerLock(); this.hud.showNotification('RESPAWNED! GET READY TO FIGHT.'); } toggleCRTFilter(enabled) { this.crtFilterEnabled = enabled; const scanlineElem = document.getElementById('crt-scanlines'); if (scanlineElem) { if (enabled) scanlineElem.classList.remove('hidden'); else scanlineElem.classList.add('hidden'); } } // ---------------------------------------------------- // MAIN GAME LOOP // ---------------------------------------------------- loop(currentTime) { requestAnimationFrame(this.loop); const delta = Math.min(0.1, (currentTime - this.lastTime) / 1000.0); this.lastTime = currentTime; if (this.state === 'playing') { // Update all game subsystems this.player.update(delta); this.map.update(delta); this.weapons.update(delta); this.enemies.update(delta); this.items.update(delta); this.engine.update(delta); this.hud.update(delta); } // Always render 3D Scene this.engine.render(); } } // Global bootstrap window.addEventListener('DOMContentLoaded', () => { window.game = new DoomGame(); });