Resonance ping: right click with the drill lights up nearby veins through fog (t50)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-27 16:47:35 -04:00
co-authored by Claude Opus 5.5
parent ef4ba6d24a
commit 569ec6e5b6
9 changed files with 103 additions and 11 deletions
+36
View File
@@ -109,6 +109,42 @@ function drawFlowRates() {
}
ctx.restore();
}
// The resonance ping's echo: a ring spreading from the bot, the veins it found lighting up inside
// it, then fading once it has gone out. The veins are drawn once into a small image, so each
// frame is one clipped drawImage however many there are. Drawn over fog, so unexplored rock shows.
const PING_SPEED = 160, PING_FADE = 4500;
function pingImage(p) {
const size = p.r * 2 + 1, c = document.createElement('canvas'); c.width = c.height = size;
const g = c.getContext('2d'), img = g.createImageData(size, size), d = img.data, ox = Math.floor(p.x - p.r), oy = Math.floor(p.y - p.r);
for (const i of p.cells) {
const x = i % W - ox, y = ((i / W) | 0) - oy;
if (x < 0 || y < 0 || x >= size || y >= size) continue;
const k = (y * size + x) * 4, m = mat[i];
d[k] = Math.min(255, COLR[m] + 90); d[k + 1] = Math.min(255, COLG[m] + 90); d[k + 2] = Math.min(255, COLB[m] + 90); d[k + 3] = 220;
}
g.putImageData(img, 0, 0);
return { c, ox, oy };
}
function drawPing() {
const p = GAME.ping;
if (!p) return;
const ms = performance.now() - p.t0, front = ms / 1000 * PING_SPEED, done = p.r / PING_SPEED * 1000;
if (ms > done + PING_FADE) { GAME.ping = null; return; }
if (!p.img) p.img = pingImage(p);
const ctx = R.ctx, zp = R.zp, c = worldToScreenPx(p.x, p.y), o = worldToScreenPx(p.img.ox, p.img.oy);
ctx.save();
ctx.beginPath(); ctx.arc(c.x, c.y, Math.min(front, p.r + 1) * zp, 0, Math.PI * 2); ctx.clip();
ctx.globalAlpha = ms < done ? 1 : Math.max(0, 1 - (ms - done) / PING_FADE);
ctx.imageSmoothingEnabled = false;
ctx.drawImage(p.img.c, o.x, o.y, p.img.c.width * zp, p.img.c.height * zp);
ctx.restore();
if (front < p.r) {
ctx.save();
ctx.strokeStyle = `rgba(160,225,255,${0.85 * (1 - front / p.r)})`; ctx.lineWidth = Math.max(2, zp * 0.8);
ctx.beginPath(); ctx.arc(c.x, c.y, front * zp, 0, Math.PI * 2); ctx.stroke();
ctx.restore();
}
}
// Outline a run of blocks: strong while it is being edited, faint when pointed at
function drawRunOutline(run, strong) {
if (!run || !run.length) return;