|
|
|
|
@ -97,20 +97,83 @@
|
|
|
|
|
let particles = [];
|
|
|
|
|
let lastTime = 0;
|
|
|
|
|
|
|
|
|
|
const walls = [
|
|
|
|
|
...brickWall(120, 80, TILE, TILE * 3),
|
|
|
|
|
...brickWall(240, 120, TILE * 4, TILE),
|
|
|
|
|
...steelWall(520, 80, TILE, TILE * 3),
|
|
|
|
|
...brickWall(640, 160, TILE * 2, TILE),
|
|
|
|
|
...brickWall(80, 320, TILE * 3, TILE),
|
|
|
|
|
...brickWall(280, 280, TILE, TILE * 3),
|
|
|
|
|
...brickWall(400, 360, TILE * 4, TILE),
|
|
|
|
|
...steelWall(640, 360, TILE, TILE * 3),
|
|
|
|
|
...steelWall(560, 240, TILE * 2, TILE),
|
|
|
|
|
...brickWall(160, 480, TILE * 2, TILE),
|
|
|
|
|
...brickWall(480, 500, TILE * 3, TILE),
|
|
|
|
|
// Static brick layout (kept stable across games). Steel walls are randomized
|
|
|
|
|
// on every reset, so they are added separately in resetGame via regenerateWalls.
|
|
|
|
|
const BRICK_LAYOUT = [
|
|
|
|
|
[120, 80, TILE, TILE * 3],
|
|
|
|
|
[240, 120, TILE * 4, TILE],
|
|
|
|
|
[640, 160, TILE * 2, TILE],
|
|
|
|
|
[80, 320, TILE * 3, TILE],
|
|
|
|
|
[280, 280, TILE, TILE * 3],
|
|
|
|
|
[400, 360, TILE * 4, TILE],
|
|
|
|
|
[160, 480, TILE * 2, TILE],
|
|
|
|
|
[480, 500, TILE * 3, TILE],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Rectangles that steel walls must avoid so spawns are not blocked or boxed in.
|
|
|
|
|
// Each entry is padded around a player/enemy starting position.
|
|
|
|
|
const SPAWN_KEEPOUTS = [
|
|
|
|
|
spawnKeepout(384, 536), // player
|
|
|
|
|
spawnKeepout(84, 64),
|
|
|
|
|
spawnKeepout(384, 64),
|
|
|
|
|
spawnKeepout(684, 64),
|
|
|
|
|
spawnKeepout(84, 220),
|
|
|
|
|
spawnKeepout(684, 260),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
let walls = [];
|
|
|
|
|
|
|
|
|
|
function spawnKeepout(x, y) {
|
|
|
|
|
// Generous margin (1.5 tiles) around the spawn keeps lanes open so tanks
|
|
|
|
|
// are never immediately boxed in by randomized steel.
|
|
|
|
|
const margin = TILE * 1.5;
|
|
|
|
|
return {
|
|
|
|
|
x: x - margin,
|
|
|
|
|
y: y - margin,
|
|
|
|
|
w: TANK_SIZE + margin * 2,
|
|
|
|
|
h: TANK_SIZE + margin * 2,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function buildBrickWalls() {
|
|
|
|
|
const pieces = [];
|
|
|
|
|
for (const [x, y, w, h] of BRICK_LAYOUT) {
|
|
|
|
|
pieces.push(...brickWall(x, y, w, h));
|
|
|
|
|
}
|
|
|
|
|
return pieces;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function randomSteelWalls(occupied) {
|
|
|
|
|
// 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 cols = Math.floor(WIDTH / TILE);
|
|
|
|
|
const rows = Math.floor(HEIGHT / TILE);
|
|
|
|
|
let attempts = 0;
|
|
|
|
|
while (pieces.length < count && attempts < count * 20) {
|
|
|
|
|
attempts += 1;
|
|
|
|
|
const vertical = Math.random() < 0.5;
|
|
|
|
|
const length = (2 + Math.floor(Math.random() * 2)) * TILE; // 2-3 tiles long
|
|
|
|
|
const x = Math.floor(Math.random() * cols) * TILE;
|
|
|
|
|
const y = Math.floor(Math.random() * rows) * TILE;
|
|
|
|
|
const w = vertical ? TILE : length;
|
|
|
|
|
const h = vertical ? length : TILE;
|
|
|
|
|
const candidate = { x, y, w, h };
|
|
|
|
|
if (x + w > WIDTH || y + h > HEIGHT) continue;
|
|
|
|
|
if (SPAWN_KEEPOUTS.some((zone) => intersects(candidate, zone))) continue;
|
|
|
|
|
if (occupied.some((area) => intersects(candidate, area))) continue;
|
|
|
|
|
pieces.push(...steelWall(x, y, w, h));
|
|
|
|
|
occupied.push(candidate);
|
|
|
|
|
}
|
|
|
|
|
return pieces;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function regenerateWalls() {
|
|
|
|
|
const bricks = buildBrickWalls();
|
|
|
|
|
walls = [...bricks, ...randomSteelWalls([...bricks])];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function rect(x, y, w, h, type = "brick") {
|
|
|
|
|
return { x, y, w, h, type, destructible: type === "brick" };
|
|
|
|
|
}
|
|
|
|
|
@ -153,6 +216,7 @@
|
|
|
|
|
lives = 3;
|
|
|
|
|
bullets = [];
|
|
|
|
|
particles = [];
|
|
|
|
|
regenerateWalls();
|
|
|
|
|
player = tank(384, 536, "#77b255", "up", "player");
|
|
|
|
|
enemies = [
|
|
|
|
|
tank(84, 64, "#db5a42", "down"),
|
|
|
|
|
@ -565,6 +629,7 @@
|
|
|
|
|
if (stopAction) stopAction.addEventListener("click", endGame);
|
|
|
|
|
if (endAction) endAction.addEventListener("click", endGame);
|
|
|
|
|
|
|
|
|
|
regenerateWalls();
|
|
|
|
|
player = tank(384, 536, "#77b255", "up", "player");
|
|
|
|
|
updateHud();
|
|
|
|
|
setState("menu");
|
|
|
|
|
|