Space Shooter

(function () { function startWhenReady() { const canvas = document.getElementById("game"); if (!canvas) { setTimeout(startWhenReady, 200); return; } const ctx = canvas.getContext("2d"); const W = canvas.width, H = canvas.height; let score = 0, hp = 3, gameOver = false; const keys = Object.create(null); let bullets = [], enemies = []; const player = { x: W / 2 - 20, y: H - 60, w: 40, h: 40, speed: 6, cooldown: 0 }; window.addEventListener("keydown", (e) => (keys[e.key] = true)); window.addEventListener("keyup", (e) => (keys[e.key] = false)); function overlap(a, b) { return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y; } function shoot() { if (player.cooldown <= 0) { bullets.push({ x: player.x + player.w / 2 - 3, y: player.y, w: 6, h: 15 }); player.cooldown = 15; } } function spawnEnemy() { enemies.push({ x: Math.random() * (W - 40), y: -40, w: 40, h: 40, speed: 2 + Math.random() * 2 }); } function update() { if (gameOver) return; if (keys["ArrowLeft"] || keys["a"] || keys["A"]) player.x -= player.speed; if (keys["ArrowRight"] || keys["d"] || keys["D"]) player.x += player.speed; if (keys[" "]) shoot(); player.x = Math.max(0, Math.min(W - player.w, player.x)); player.cooldown = Math.max(0, player.cooldown - 1); bullets.forEach((b) => (b.y -= 8)); bullets = bullets.filter((b) => b.y > -20); enemies.forEach((e) => (e.y += e.speed)); for (let ei = enemies.length - 1; ei >= 0; ei--) { const e = enemies[ei]; for (let bi = bullets.length - 1; bi >= 0; bi--) { const b = bullets[bi]; if (overlap(b, e)) { enemies.splice(ei, 1); bullets.splice(bi, 1); score += 100; break; } } if (overlap(player, e)) { enemies.splice(ei, 1); hp -= 1; if (hp <= 0) gameOver = true; } } enemies = enemies.filter((e) => e.y < H + 50); if (Math.random() < 0.02) spawnEnemy(); } function draw() { ctx.fillStyle = "#000"; ctx.fillRect(0, 0, W, H); ctx.fillStyle = "cyan"; ctx.beginPath(); ctx.moveTo(player.x + player.w / 2, player.y); ctx.lineTo(player.x + player.w, player.y + player.h); ctx.lineTo(player.x, player.y + player.h); ctx.closePath(); ctx.fill(); ctx.fillStyle = "yellow"; bullets.forEach((b) => ctx.fillRect(b.x, b.y, b.w, b.h)); ctx.fillStyle = "red"; enemies.forEach((e) => ctx.fillRect(e.x, e.y, e.w, e.h)); ctx.fillStyle = "#fff"; ctx.font = "20px Arial"; ctx.fillText("Score: " + score, 20, 30); ctx.fillText("HP: " + hp, 20, 60); if (gameOver) { ctx.font = "40px Arial"; ctx.fillText("GAME OVER", W / 2 - 120, H / 2); } } function loop() { update(); draw(); requestAnimationFrame(loop); } loop(); } if (document.readyState === "loading") { document.addEventListener("DOMContentLoaded", startWhenReady); } else { startWhenReady(); } })();