From a3e49dffb92ddd17642c7a5e6292422745139b51 Mon Sep 17 00:00:00 2001 From: OpenClaw Engineer Date: Tue, 3 Mar 2026 20:41:43 -0600 Subject: [PATCH] feat: unlock falling meteor hazards after score > 250 --- js/game.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/js/game.js b/js/game.js index 88f5105..066080f 100644 --- a/js/game.js +++ b/js/game.js @@ -34,6 +34,8 @@ const state = { ], pterodactyls: [], pteroSpawnTimer: 0, + meteors: [], + meteorSpawnTimer: 0, player: { x: 160, y: 0, @@ -111,6 +113,15 @@ function drawPterodactyls() { } } +function drawMeteors() { + ctx.fillStyle = '#6b4d2e'; + for (const m of state.meteors) { + const sx = m.x - state.cameraX; + if (sx + m.width < 0 || sx > canvas.width) continue; + ctx.fillRect(sx, m.y, m.width, m.height); + } +} + function intersects(a, b) { return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y; } @@ -189,6 +200,27 @@ function updatePterodactyls(dt) { state.pterodactyls = state.pterodactyls.filter((f) => f.x + f.width > state.cameraX - 150); } +function updateMeteors(dt) { + if (state.score <= 250) return; + + state.meteorSpawnTimer -= dt; + if (state.meteorSpawnTimer <= 0) { + const spawnX = state.cameraX + 80 + Math.random() * (canvas.width - 160); + state.meteors.push({ x: spawnX, y: -30, width: 24, height: 30, vy: 420 }); + state.meteorSpawnTimer = 1.5; + } + + const p = state.player; + for (const m of state.meteors) { + m.y += m.vy * dt; + if (intersects(p, m)) { + applyHit('Meteor strike!'); + m.y = canvas.height + 100; + } + } + state.meteors = state.meteors.filter((m) => m.y < canvas.height + 80); +} + function updatePlayer(dt) { const p = state.player; let move = 0; @@ -253,12 +285,14 @@ function tick(ts) { updatePlayer(dt); updateAnts(dt); updatePterodactyls(dt); + updateMeteors(dt); } ctx.clearRect(0, 0, canvas.width, canvas.height); drawBackground(); drawAnts(); drawPterodactyls(); + drawMeteors(); drawTRex(state.player); drawDeathText();