diff --git a/index.html b/index.html index ee4d843..36a4d1f 100644 --- a/index.html +++ b/index.html @@ -23,8 +23,8 @@ 0
- Lives - 3 + Health + 100%
Enemies diff --git a/src/game.js b/src/game.js index 245cbc6..3d604c6 100644 --- a/src/game.js +++ b/src/game.js @@ -34,7 +34,7 @@ hud.style.cssText = "width:800px;max-width:100%;margin:8px auto;color:#e8eadf;font:16px/1.4 system-ui,sans-serif;display:flex;gap:18px;flex-wrap:wrap;"; hud.innerHTML = - 'Score: 0 Lives: 3 Enemies: 0'; + 'Score: 0 Health: 100% Enemies: 0'; canvas.parentNode.insertBefore(hud, canvas.nextSibling); } @@ -80,6 +80,8 @@ const FIRE_COOLDOWN = 0.34; const ENEMY_FIRE_COOLDOWN = 1.35; const BRICK_SIZE = 20; + const PLAYER_MAX_HEALTH = 100; + const PLAYER_HIT_DAMAGE = 34; const DIRS = { up: { x: 0, y: -1 }, down: { x: 0, y: 1 }, @@ -90,7 +92,7 @@ const keys = new Set(); let state = "menu"; let score = 0; - let lives = 3; + let health = PLAYER_MAX_HEALTH; let player; let enemies = []; let bullets = []; @@ -147,14 +149,15 @@ // Generate a handful of vertical/horizontal steel segments at random tile // positions, skipping any that overlap a spawn keep-out zone. const pieces = []; - const count = 3 + Math.floor(Math.random() * 3); // 3-5 steel walls + const segmentCount = 5 + Math.floor(Math.random() * 3); // 5-7 steel wall segments const cols = Math.floor(WIDTH / TILE); const rows = Math.floor(HEIGHT / TILE); + let placedSegments = 0; let attempts = 0; - while (pieces.length < count && attempts < count * 20) { + while (placedSegments < segmentCount && attempts < segmentCount * 30) { attempts += 1; const vertical = Math.random() < 0.5; - const length = (2 + Math.floor(Math.random() * 2)) * TILE; // 2-3 tiles long + const length = (2 + Math.floor(Math.random() * 3)) * TILE; // 2-4 tiles long const x = Math.floor(Math.random() * cols) * TILE; const y = Math.floor(Math.random() * rows) * TILE; const w = vertical ? TILE : length; @@ -165,6 +168,7 @@ if (occupied.some((area) => intersects(candidate, area))) continue; pieces.push(...steelWall(x, y, w, h)); occupied.push(candidate); + placedSegments += 1; } return pieces; } @@ -213,7 +217,7 @@ function resetGame() { score = 0; - lives = 3; + health = PLAYER_MAX_HEALTH; bullets = []; particles = []; regenerateWalls(); @@ -278,7 +282,7 @@ function updateHud() { scoreEl.textContent = score; - livesEl.textContent = lives; + livesEl.textContent = `${health}%`; enemiesEl.textContent = enemies.filter((enemy) => enemy.alive).length; } @@ -445,9 +449,9 @@ continue; } } else if (intersects(bullet, player)) { - lives -= 1; + health = Math.max(0, health - PLAYER_HIT_DAMAGE); spark(player.x + player.w / 2, player.y + player.h / 2, "#77b255"); - if (lives <= 0) { + if (health <= 0) { player.alive = false; setState("gameOver"); } else { @@ -551,13 +555,13 @@ let glowColor, glowBlur, outerColor, innerColor, coreColor; if (isPlayer) { - if (lives >= 3) { + if (health > 66) { glowColor = "rgba(132, 238, 212, 0.75)"; glowBlur = 12; outerColor = "#e8fff7"; innerColor = "#102822"; coreColor = entity.color; - } else if (lives === 2) { + } else if (health > 33) { glowColor = "rgba(240, 182, 70, 0.45)"; glowBlur = 8; outerColor = "#c8c0a0"; @@ -585,7 +589,7 @@ ctx.fillStyle = "rgba(255,255,255,0.18)"; ctx.fillRect(-7, -8, 14, 16); - if (isPlayer && lives === 2) { + if (isPlayer && health <= 66 && health > 33) { ctx.strokeStyle = "rgba(30, 20, 10, 0.55)"; ctx.lineWidth = 2; ctx.beginPath(); @@ -601,7 +605,7 @@ ctx.fillRect(5, -4, 4, 4); } - if (isPlayer && lives <= 1) { + if (isPlayer && health <= 33) { ctx.strokeStyle = "rgba(80, 10, 10, 0.6)"; ctx.lineWidth = 2; ctx.beginPath(); @@ -623,7 +627,7 @@ } ctx.fillStyle = isPlayer ? "#f4fff8" : "#1b0805"; - if (isPlayer && lives <= 1 && Math.floor(Date.now() / 300) % 2 === 0) { + if (isPlayer && health <= 33 && Math.floor(Date.now() / 300) % 2 === 0) { ctx.globalAlpha = 0.3; } ctx.fillRect(-4, -26, 8, 20); @@ -633,7 +637,7 @@ ctx.fillRect(-10, -2, 20, 4); ctx.fillStyle = "#79e5c9"; ctx.fillRect(-5, -5, 10, 10); - if (lives <= 1 && Math.floor(Date.now() / 300) % 2 === 0) { + if (health <= 33 && Math.floor(Date.now() / 300) % 2 === 0) { ctx.fillStyle = "rgba(212, 93, 69, 0.7)"; ctx.beginPath(); ctx.moveTo(0, -14);