Files
leggenda-del-regolo/src/engine/rinquarto-render.js
T

78 lines
4.8 KiB
JavaScript

import { LEN, WID, R, VIEW, WINDUP } from './biliardo.js';
import { table, sphere, pin, cue } from './biliardo-render.js';
import { guide, canThrow, shooter } from './rinquarto.js';
import { text, panel } from './bocce-render.js';
const sx = x => VIEW.x + x * VIEW.k, sy = y => VIEW.y + y * VIEW.k;
const NAME = { andrea: 'Andrea', bertovo: 'Trappizzio Berti' };
// La traiettoria del tiro: resta sul tavolo finché non si va avanti, con le sponde numerate e il contatto che decide.
function trail(ctx, c) {
if (c.trail.length < 2) return;
const good = c.attempt.point, done = c.step === 'review';
ctx.strokeStyle = done ? (good ? '#b9e5b3' : '#ffbf9f') : '#fff8dccc'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.moveTo(sx(c.trail[0][0]), sy(c.trail[0][1]));
for (const [x, y] of c.trail.slice(1)) ctx.lineTo(sx(x), sy(y));
ctx.stroke();
c.attempt.marks.forEach((m, i) => {
ctx.fillStyle = '#17160f'; ctx.beginPath(); ctx.arc(sx(m.x), sy(m.y), 5, 0, Math.PI * 2); ctx.fill();
text(ctx, String(i + 1), sx(m.x), sy(m.y) + 0.5, 7, '#ffe28a', 'center');
});
if (done && c.attempt.hit) {
const { x, y } = c.attempt.hit;
ctx.strokeStyle = good ? '#b9e5b3' : '#ff6a4a'; ctx.lineWidth = 2;
ctx.beginPath(); ctx.arc(sx(x), sy(y), R * VIEW.k + 4, 0, Math.PI * 2); ctx.stroke();
}
}
export function drawRinquarto(ctx, c, def, bg) {
ctx.save(); ctx.imageSmoothingEnabled = false;
table(ctx, bg);
ctx.save(); ctx.beginPath(); ctx.rect(VIEW.x - 15, VIEW.y - 15, LEN * VIEW.k + 30, WID * VIEW.k + 30); ctx.clip();
if (canThrow(c)) {
const points = guide(c);
if (points.length) {
ctx.strokeStyle = '#fff8dc'; ctx.lineWidth = 1; ctx.setLineDash([4, 3]);
ctx.beginPath(); ctx.moveTo(sx(points[0][0]), sy(points[0][1]));
for (const [x, y] of points.slice(1)) ctx.lineTo(sx(x), sy(y));
ctx.stroke(); ctx.setLineDash([]);
}
const b = c.balls.player;
cue(ctx, b.x, b.y, c.angle, R * VIEW.k + 6 + (c.charging ? 26 : 10));
} else if (c.visual.shot && c.windup > 0) {
const s = c.visual.shot;
cue(ctx, s.x, s.y, s.angle, R * VIEW.k + 32 * c.windup / WINDUP);
}
trail(ctx, c);
for (const p of c.pins) pin(ctx, p, c.visual.time);
// Il bersaglio ha un anello che pulsa; i disturbi una croce grossa, che si vede anche sul telefono.
const tgt = c.balls.cpu, pulse = 1 + Math.sin(c.visual.time * 4) * 0.5;
ctx.strokeStyle = '#ffe28a'; ctx.lineWidth = 1.5;
ctx.beginPath(); ctx.arc(sx(tgt.x), sy(tgt.y), R * VIEW.k + 3 + pulse, 0, Math.PI * 2); ctx.stroke();
for (const b of Object.values(c.balls)) {
sphere(ctx, b.role, sx(b.x), sy(b.y), R * VIEW.k);
if (!['player', 'cpu'].includes(b.role)) {
const k = R * VIEW.k;
ctx.strokeStyle = '#1b0d29'; ctx.lineWidth = 2;
ctx.beginPath(); ctx.moveTo(sx(b.x) - k, sy(b.y) - k); ctx.lineTo(sx(b.x) + k, sy(b.y) + k);
ctx.moveTo(sx(b.x) + k, sy(b.y) - k); ctx.lineTo(sx(b.x) - k, sy(b.y) + k); ctx.stroke();
}
}
ctx.restore();
// In alto: chi tira, il punteggio, le sponde; l'esito sta qui, così non copre il tavolo.
ctx.fillStyle = '#17160ff0'; ctx.fillRect(54, 4, 532, 64);
text(ctx, c.skill.training ? 'I RINQUARTI DI TRAPPIZZIO BERTI · ALLENAMENTO' : 'I RINQUARTI DI TRAPPIZZIO BERTI', 320, 13, 9, '#efd49e', 'center');
const score = c.skill.training ? 'senza punti' : `Andrea ${c.score.andrea} Trappizzio Berti ${c.score.bertovo}`;
text(ctx, `Posizione ${c.position}/${c.skill.positions} ${score} Sponde ${c.attempt.cushions}/${c.skill.cushions}`, 320, 29, 9, '#fff0c8', 'center');
const who = NAME[shooter(c)];
const line = c.step === 'review' ? c.line : c.step === 'think' ? 'Tira Trappizzio Berti…' : c.step === 'rolling' ? `Tira ${who}…` : `Tocca ad ${who}: «Oh tirami questo rinquarto!?»`;
text(ctx, line, 320, 45, 8, c.step === 'review' ? (c.attempt.point ? '#b9e5b3' : '#ffbf9f') : '#9fd0ff', 'center');
if (c.step === 'review') text(ctx, c.last ? 'Tocca per il risultato' : 'Tocca o premi Prossima', 320, 59, 7, '#d9ccba', 'center');
if (c.step === 'result') {
const r = c.result, title = r.training ? 'ALLENAMENTO FINITO' : r.winner === 'player' ? 'HAI BATTUTO TRAPPIZZIO BERTI!' : r.winner === 'cpu' ? 'HA VINTO TRAPPIZZIO BERTI' : 'PARI';
panel(ctx, 155, 145, 330, 80);
text(ctx, title, 320, 166, 12, r.winner === 'player' ? '#b9e5b3' : '#efd49e', 'center');
if (!r.training) text(ctx, `Andrea ${r.points.andrea} · Trappizzio Berti ${r.points.bertovo}, su ${c.skill.positions} posizioni`, 320, 190, 8, '#efd49e', 'center');
text(ctx, 'Torna da Trappizzio Berti per uscire.', 320, 210, 8, '#d9ccba', 'center');
}
ctx.restore();
}