Files

141 lines
5.3 KiB
JavaScript

/* ============================================================
DSP ARCADE — shared UI: load screen, title, HUD, pause,
game over, high-score entry. Draws on top of the game canvas.
============================================================ */
(function () {
'use strict';
const { STATE } = window.DSP;
function text(ctx, str, x, y, size, color, align = 'center') {
ctx.font = `${size}px "Press Start 2P", monospace`;
ctx.textAlign = align;
ctx.textBaseline = 'middle';
ctx.fillStyle = color;
ctx.fillText(str, x, y);
}
function glowText(ctx, str, x, y, size, color, glow) {
ctx.save();
ctx.shadowColor = glow || color;
ctx.shadowBlur = 12;
text(ctx, str, x, y, size, color);
ctx.restore();
}
function blink(on) { return Math.floor(performance.now() / 400) % 2 === on; }
function draw(game) {
const ctx = game.ctx;
const W = game.W, H = game.H;
const cx = W / 2;
switch (game.state) {
case STATE.LOADING: {
ctx.fillStyle = '#05010d';
ctx.fillRect(0, 0, W, H);
for (let i = 0; i < 40; i++) {
const sx = (i * 97 + game.time * 0.3) % W;
const sy = (i * 53) % H;
ctx.fillStyle = i % 3 === 0 ? '#ff2d95' : '#7df9ff';
ctx.globalAlpha = 0.3 + (i % 5) * 0.12;
ctx.fillRect(sx, sy, 2, 2);
}
ctx.globalAlpha = 1;
glowText(ctx, game.title, cx, H * 0.3, 20, '#ff2d95');
const step = game.loadSteps[Math.min(game.loadStep, game.loadSteps.length - 1)];
text(ctx, step + '...', cx, H * 0.5, 8, '#7df9ff');
const bw = W * 0.5, bh = 14;
const bx = cx - bw / 2, by = H * 0.6;
ctx.strokeStyle = '#7df9ff';
ctx.lineWidth = 2;
ctx.strokeRect(bx, by, bw, bh);
ctx.fillStyle = '#ff2d95';
ctx.fillRect(bx + 2, by + 2, (bw - 4) * Math.min(1, game.loadProgress), bh - 4);
text(ctx, Math.floor(Math.min(1, game.loadProgress) * 100) + '%', cx, by + bh + 16, 8, '#ffffff');
break;
}
case STATE.TITLE: {
ctx.fillStyle = 'rgba(5,1,13,0.75)';
ctx.fillRect(0, 0, W, H);
glowText(ctx, game.title, cx, H * 0.28, 22, '#ff2d95');
text(ctx, 'DIGITAL SPACEPORT ARCADE', cx, H * 0.28 + 30, 7, '#7df9ff');
if (blink(0)) text(ctx, 'PRESS SPACE TO START', cx, H * 0.55, 10, '#ffe14d');
text(ctx, 'HI-SCORE: ' + String(game.best).padStart(6, '0'), cx, H * 0.68, 8, '#7dff5e');
text(ctx, 'M: MUTE P: PAUSE', cx, H * 0.85, 7, '#8a7fb5');
break;
}
case STATE.PLAYING:
case STATE.PAUSED: {
ctx.fillStyle = 'rgba(5,1,13,0.55)';
ctx.fillRect(0, 0, W, 26);
text(ctx, 'SCORE ' + String(game.score).padStart(6, '0'), 8, 13, 8, '#ffffff', 'left');
text(ctx, 'HI ' + String(game.best).padStart(6, '0'), W / 2, 13, 8, '#7dff5e');
text(ctx, 'LV ' + game.level, W - 8, 13, 8, '#ffe14d', 'right');
const hearts = Math.min(game.lives, 5);
for (let i = 0; i < hearts; i++) {
const img = window.DSP_SPRITES.get('heart', 2);
ctx.drawImage(img, 8 + i * 18, 32);
}
if (game.mouseCaptured !== undefined) {
if (game.mouseCaptured) {
text(ctx, 'MOUS FANGEN - ESC FREIGIBT', W - 8, 44, 7, '#ff7de9', 'right');
} else if (game.state === STATE.PLAYING) {
text(ctx, 'KLICK IN CANVAS = MAUS FANGEN', W - 8, 44, 7, '#8a7fb5', 'right');
}
}
if (game.state === STATE.PAUSED) {
ctx.fillStyle = 'rgba(5,1,13,0.7)';
ctx.fillRect(0, 0, W, H);
glowText(ctx, 'PAUSED', cx, H * 0.45, 20, '#7df9ff');
text(ctx, 'PRESS P TO RESUME', cx, H * 0.58, 8, '#ffffff');
}
break;
}
case STATE.GAMEOVER: {
ctx.fillStyle = 'rgba(5,1,13,0.8)';
ctx.fillRect(0, 0, W, H);
glowText(ctx, 'GAME OVER', cx, H * 0.3, 22, '#ff4d6d');
text(ctx, 'SCORE ' + String(game.score).padStart(6, '0'), cx, H * 0.45, 10, '#ffffff');
if (game.gameOverRank > 0) {
text(ctx, 'RANK #' + game.gameOverRank + ' ON THE BOARD', cx, H * 0.55, 8, '#ffe14d');
}
if (blink(0)) text(ctx, 'PRESS SPACE', cx, H * 0.7, 9, '#7df9ff');
break;
}
case STATE.HIGHSCORE: {
ctx.fillStyle = 'rgba(5,1,13,0.85)';
ctx.fillRect(0, 0, W, H);
glowText(ctx, 'NEW HIGH SCORE!', cx, H * 0.25, 14, '#ffe14d');
text(ctx, 'SCORE ' + String(game.score).padStart(6, '0'), cx, H * 0.38, 10, '#ffffff');
text(ctx, 'ENTER PILOT NAME', cx, H * 0.5, 8, '#7df9ff');
const name = (game._hsName || '').toUpperCase();
const cursor = blink(0) ? '_' : ' ';
text(ctx, (name + cursor).padStart(9, ' '), cx, H * 0.6, 14, '#7dff5e');
text(ctx, 'TYPE NAME + ENTER', cx, H * 0.72, 7, '#8a7fb5');
break;
}
}
}
window.addEventListener('keydown', (e) => {
const g = window.DSP_ACTIVE_GAME;
if (!g || g.state !== STATE.HIGHSCORE) return;
if (e.code === 'Enter') return;
if (e.code === 'Backspace') {
g._hsName = (g._hsName || '').slice(0, -1);
e.preventDefault();
return;
}
if (e.key && e.key.length === 1 && /[a-zA-Z]/.test(e.key)) {
g._hsName = ((g._hsName || '') + e.key).slice(0, 8);
e.preventDefault();
}
});
window.DSP_UI = { draw };
})();