180 lines
5.9 KiB
JavaScript
Executable File
180 lines
5.9 KiB
JavaScript
Executable File
/**
|
|
* 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();
|
|
});
|