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);