Pulsante «?» (o H) che mostra per qualche secondo cosa si può toccare; mappa che si scorre sul telefono

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017egeN2amL84ErjfgQFtEDn
This commit is contained in:
2026-10-23 21:57:25 +02:00
co-authored by Claude Opus 5.5
parent a5a6834a37
commit c0d643d05d
5 changed files with 46 additions and 6 deletions
+25 -1
View File
@@ -102,7 +102,7 @@ function drawSprite(ctx, { atlas, img }, frame, x, y, scale, facing, size = 1) {
ctx.restore();
}
export function render(ctx, game, { hover } = {}) {
export function render(ctx, game, { hover, spots } = {}) {
const scene = game.scene, s = game.state, bg = backgrounds.get(scene.background);
ctx.imageSmoothingEnabled = false;
ctx.clearRect(0, 0, WIDTH, HEIGHT);
@@ -119,6 +119,7 @@ export function render(ctx, game, { hover } = {}) {
if (sheet) queue.push({ y: p.at[1], draw: () => drawSprite(ctx, sheet, game.personPose(p), ...p.at, game.scaleAt(p.at[1]), p.facing ?? 1, p.size) });
}
for (const q of queue.sort((a, b) => a.y - b.y)) q.draw();
if (spots) drawSpots(ctx, game);
if (hover) {
ctx.strokeStyle = 'rgba(255,255,255,0.35)';
ctx.setLineDash([3, 3]);
@@ -126,3 +127,26 @@ export function render(ctx, game, { hover } = {}) {
ctx.setLineDash([]);
}
}
// Il pulsante «?»: un segno su ogni cosa che si può toccare, col suo nome. Le uscite in giallo, il resto in bianco.
function drawSpots(ctx, game) {
ctx.save();
ctx.font = '6px "Press Start 2P", monospace';
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
for (const h of game.hotspots()) {
const [x, y, w, hh] = h.box, cx = Math.round(x + w / 2), cy = Math.round(y + hh / 2);
const color = h.exit ? '#ffd27a' : '#ffffff';
ctx.fillStyle = 'rgba(0,0,0,0.55)';
ctx.fillRect(cx - 4, cy - 4, 9, 9);
ctx.fillStyle = color;
ctx.fillRect(cx - 3, cy - 3, 7, 7);
ctx.lineWidth = 3;
ctx.strokeStyle = '#000';
// Il nome resta dentro la scena anche per le uscite sui bordi.
const half = ctx.measureText(h.name).width / 2, tx = Math.max(half + 2, Math.min(WIDTH - half - 2, cx)), ty = Math.max(10, cy - 6);
ctx.strokeText(h.name, tx, ty);
ctx.fillText(h.name, tx, ty);
}
ctx.restore();
}
+11 -1
View File
@@ -102,9 +102,17 @@ function openMap() {
return b;
}));
$('map').hidden = false;
// Sul telefono la pianta scorre: si parte col posto dove si è, al centro.
board.querySelector('.here')?.scrollIntoView({ block: 'center', inline: 'center' });
}
$('map-button').addEventListener('click', openMap);
// --- «?»: per qualche secondo si vede tutto quello che si può toccare (sul telefono non c'è il mouse da passarci sopra).
const SPOTS_TIME = 3500;
let spotsUntil = 0;
const showSpots = () => { spotsUntil = performance.now() + SPOTS_TIME; };
$('spots-button').addEventListener('click', showSpots);
// --- Pausa: ferma il gioco; da qui mappa, crediti o ritorno al titolo (la partita resta salvata per «Continua»).
function openPause() {
if (!running) return;
@@ -242,6 +250,7 @@ window.addEventListener('keydown', e => {
if (!$('pause').hidden) { if (e.key === 'Escape') closePause(); return; }
if (!$('map').hidden) { if (e.key === 'Escape' || e.key === 'p' || e.key === 'P') $('map').hidden = true; return; }
if ((e.key === 'p' || e.key === 'P') && running) { openMap(); return; }
if ((e.key === 'h' || e.key === 'H') && running) { showSpots(); return; }
if (!$('intro').hidden && [' ', 'Enter'].includes(e.key)) { e.preventDefault(); nextIntro(); return; }
if (e.key === 'm' || e.key === 'M') { music.toggle(); saveAudio(); showSound(); return; }
if (!running) return;
@@ -280,6 +289,7 @@ function updateUi() {
// Il pulsante della mappa c'è solo in partita, fuori dai dialoghi, e quando c'è almeno un altro posto dove andare.
$('map-button').hidden = !running || !!game.dialogue || game.mapPlaces().length < 2;
$('pause-button').hidden = !running;
$('spots-button').hidden = !running;
if (game.state.ended && !game.speech && !game.queue.length) {
running = false;
$('ending').hidden = false;
@@ -299,7 +309,7 @@ function frame(now) {
if (running && now - idleSince > IDLE_PAUSE && !game.speech && !game.walking && !game.queue.length) openPause();
if (game) {
if (running) game.update(dt);
render(ctx, game, { hover: debug && hoverTarget ? game.hotspot(hoverTarget) : null });
render(ctx, game, { hover: debug && hoverTarget ? game.hotspot(hoverTarget) : null, spots: running && now < spotsUntil });
updateUi();
}
requestAnimationFrame(frame);