Game-drawn cursors for each tool; a real pointer when building (t89)

This commit is contained in:
2026-10-29 22:59:53 -04:00
parent 974e5a6272
commit 99aae0aae0
8 changed files with 176 additions and 3 deletions
+1
View File
@@ -30,6 +30,7 @@ body {
-webkit-user-select: none; user-select: none; touch-action: none;
}
canvas#gpu, canvas#game { position: fixed; inset: 0; width: 100vw; height: 100vh; display: block; image-rendering: pixelated; cursor: none; } /* the game draws its own aim */
body.paused canvas#game { cursor: default; }
/* overlay modes (thermal lens, info overlay): a coloured frame with corner brackets, a light wash
for the info overlay so the world stays clear, and a named badge at the bottom of the screen */
#ovframe { position: fixed; inset: 0; pointer-events: none; opacity: 0; transition: opacity 0.2s; --ov: 92, 186, 166; }
+28
View File
@@ -177,6 +177,34 @@ function drawPreviews() {
ctx.restore();
if (t === 'build' && GAME.replace && !sel && !pasting) drawTag('Replace', '255,190,90', p.x + BS * zp * 1.2, p.y + BS * zp * 1.4);
drawCursorLabel(p.x, p.y, t === 'vacuum' ? GAME.brush[GAME.tool] : t === 'ignite' || t === 'drill' ? 1 : 2);
drawToolCursor();
}
// Screen-sized, hollow pointers: keep the exact aim visible between the strokes.
function drawToolCursor() {
if (!GAME.mouse.in || GAME.usingPad || GAME.paused || anyModal()) return;
const t = toolId(), sel = GAME.selDrag ? GAME.selDrag.mode : selModeHeld();
const pasting = !sel && GAME.paste && GAME.clip;
if (t === 'drill' && !sel && !pasting) return; // keep the drill's existing cross
const ctx = R.ctx, u = R.canvas.width / window.innerWidth;
const col = sel ? SEL_COL[sel] : pasting ? SEL_COL.copy : t === 'vacuum' ?
(GAME.rmb && !GAME.rmbConsumed ? '255,210,122' : '92,186,166') : t === 'ignite' ? '255,154,60' : '239,230,216';
ctx.save();
ctx.translate(GAME.mouse.x * u, GAME.mouse.y * u); ctx.scale(u, u);
ctx.setLineDash([]); ctx.lineDashOffset = 0; ctx.lineCap = 'butt'; ctx.lineJoin = 'round';
ctx.beginPath();
if (t === 'build' && !sel && !pasting) {
// Split tip converges on (0,0), leaving the aimed grain uncovered.
ctx.moveTo(0, 4); ctx.lineTo(0, 18); ctx.lineTo(4, 13);
ctx.lineTo(8, 20); ctx.lineTo(11, 18); ctx.lineTo(7, 11);
ctx.lineTo(14, 11); ctx.lineTo(3, 2);
} else {
ctx.moveTo(-10, 0); ctx.lineTo(-4, 0); ctx.moveTo(4, 0); ctx.lineTo(10, 0);
ctx.moveTo(0, -10); ctx.lineTo(0, -4); ctx.moveTo(0, 4); ctx.lineTo(0, 10);
}
ctx.strokeStyle = 'rgba(14,12,11,0.9)'; ctx.lineWidth = 3; ctx.stroke();
ctx.strokeStyle = `rgb(${col})`; ctx.lineWidth = 1.25; ctx.stroke();
ctx.restore();
}
function previewBlock(code, x, y, w, h, stroke = false, direction = -1, bx = -1, by = -1, planned = null) {