import { System } from '../core/System.js'; import { PixelFont } from '../core/PixelFont.js'; import { Palette } from '../core/Palette.js'; import { GameState, ComponentType, SystemName } from '../core/Constants.js'; /** * System to handle game menus (start, pause) */ export class MenuSystem extends System { constructor(engine) { super(SystemName.MENU); this.requiredComponents = []; // No required components this.priority = 1; // Run early this.engine = engine; this.ctx = engine.ctx; this.gameState = GameState.START; this.paused = false; } init(engine) { super.init(engine); this.setupInput(); } setupInput() { window.addEventListener('keydown', (e) => { if (e.key === 'Escape' || e.key === 'p' || e.key === 'P') { if (this.gameState === GameState.PLAYING) { this.togglePause(); } } if (e.key === 'Enter' || e.key === ' ') { if (this.gameState === GameState.START) { this.startGame(); } else if (this.gameState === GameState.PAUSED) { this.resumeGame(); } else if (this.gameState === GameState.GAME_OVER) { this.restartGame(); } } }); } showGameOver() { this.gameState = GameState.GAME_OVER; this.paused = true; } restartGame() { window.location.reload(); // Simple and effective for this project } startGame() { this.gameState = GameState.PLAYING; this.paused = false; if (!this.engine.running) { this.engine.start(); } } togglePause() { if (this.gameState === GameState.PLAYING) { this.gameState = GameState.PAUSED; this.paused = true; } else if (this.gameState === GameState.PAUSED) { this.resumeGame(); } } resumeGame() { this.gameState = GameState.PLAYING; this.paused = false; } process(_deltaTime, _entities) { // Don't update game systems if paused or at start menu if (this.gameState === GameState.PAUSED || this.gameState === GameState.START) { // Logic for system handling is moved to the update loop in Engine } } drawMenu() { const ctx = this.ctx; const width = this.engine.canvas.width; const height = this.engine.canvas.height; // Darker overlay matching palette ctx.fillStyle = 'rgba(32, 21, 51, 0.8)'; // Semi-transparent VOID ctx.fillRect(0, 0, width, height); if (this.gameState === GameState.START) { const title = 'SLIME GENESIS'; const titleW = PixelFont.getTextWidth(title, 2); PixelFont.drawText(ctx, title, (width - titleW) / 2, height / 2 - 40, Palette.CYAN, 2); const start = 'PRESS ENTER TO START'; const startW = PixelFont.getTextWidth(start, 1); PixelFont.drawText(ctx, start, (width - startW) / 2, height / 2, Palette.WHITE, 1); const instructions = [ 'WASD: MOVE | CLICK: ATTACK', 'NUMS: SKILLS | ESC: PAUSE', 'COLLECT DNA TO EVOLVE' ]; instructions.forEach((line, i) => { const lineW = PixelFont.getTextWidth(line, 1); PixelFont.drawText(ctx, line, (width - lineW) / 2, height / 2 + 25 + i * 10, Palette.ROYAL_BLUE, 1); }); } else if (this.gameState === GameState.PAUSED) { const paused = 'PAUSED'; const pausedW = PixelFont.getTextWidth(paused, 2); PixelFont.drawText(ctx, paused, (width - pausedW) / 2, 20, Palette.SKY_BLUE, 2); const resume = 'PRESS ENTER TO RESUME'; const resumeW = PixelFont.getTextWidth(resume, 1); PixelFont.drawText(ctx, resume, (width - resumeW) / 2, 45, Palette.WHITE, 1); // Draw Stats and Knowledge (Moved from HUD) const player = this.engine.getEntities().find(e => e.hasComponent(ComponentType.EVOLUTION)); const uiSystem = this.engine.systems.find(s => s.name === SystemName.UI); if (player && uiSystem) { // Draw Stats on the left uiSystem.drawStats(player, 20, 80); // Draw Learning Progress on the right uiSystem.drawSkillProgress(player, width - 110, 80); } } else if (this.gameState === GameState.GAME_OVER) { const dead = 'YOU PERISHED'; const deadW = PixelFont.getTextWidth(dead, 2); PixelFont.drawText(ctx, dead, (width - deadW) / 2, height / 2 - 30, Palette.WHITE, 2); const sub = 'YOUR DNA SUSTAINS THE CYCLE'; const subW = PixelFont.getTextWidth(sub, 1); PixelFont.drawText(ctx, sub, (width - subW) / 2, height / 2 - 5, Palette.ROYAL_BLUE, 1); const restart = 'PRESS ENTER TO REBORN'; const restartW = PixelFont.getTextWidth(restart, 1); PixelFont.drawText(ctx, restart, (width - restartW) / 2, height / 2 + 30, Palette.CYAN, 1); } } getGameState() { return this.gameState; } isPaused() { return this.paused || this.gameState === GameState.START; } }