Macchinine: si sceglie la macchinina, la forza sale da zero tenendo premuto e la spinta parte lasciando; il saluto col Chiaru («un girino alle case rosse» / «Vorrai dire un giochino!» / «Ciao Mattè»), «Si fa una gara alle macchinine?!?!», Andrea chiama Bertovo «Fabri»; musica del GP in prestito (Andrea)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GiECd9KMfjthRUnujCGSzZ
This commit is contained in:
+47
-8
@@ -19,7 +19,7 @@ export const CONTROL = [
|
||||
];
|
||||
export const HALF = 22, CAR = { len: 26, wid: 13, r: 6 }, LAPS = 1;
|
||||
// La spinta: velocità di partenza da MIN_SPEED a MAX_SPEED, e l'asfalto che frena di DECEL px/s².
|
||||
export const MIN_SPEED = 60, MAX_SPEED = 400, DECEL = 420, SWING = 1.2, LONG_PRESS = 0.6, FIXED_STEP = 1 / 120;
|
||||
export const MIN_SPEED = 60, MAX_SPEED = 400, DECEL = 420, SWING = 1.2, TAP = 0.14, FIXED_STEP = 1 / 120;
|
||||
const REST = 0.7, THINK = 1, RESTITUTION = 0.6, OUT = HALF + CAR.r, WINDOW = 30;
|
||||
// FLIP: la velocità d'urto (px/s) che ribalta la macchinina colpita; ACCOMPAGNA: quanti secondi si può restare alla
|
||||
// carica piena prima che diventi un accompagnè.
|
||||
@@ -144,14 +144,43 @@ function step(track, list, dt, events) {
|
||||
for (const car of list) if (car.vx || car.vy) follow(track, car);
|
||||
}
|
||||
|
||||
// Le macchinine fra cui scegliere (Andrea, 29 ottobre: «quando si parte fammi scegliere la macchinina»): il disegno di
|
||||
// Codex in `assets/closeups/micro/<id>.png` (e `<id>-grande.png` per la scelta) e il colore della barra in alto.
|
||||
// Il Chiaru tiene la sua blu e gialla; se la prende Andrea, lui prende la rossa.
|
||||
export const CARS = [
|
||||
{ id: 'rossa', name: 'Rossa e bianca', color: '#e0543c' },
|
||||
{ id: 'blu', name: 'Blu e gialla', color: '#3c66d8' },
|
||||
{ id: 'nera', name: 'Nera e oro', color: '#c9a23a' },
|
||||
{ id: 'azzurra', name: 'Bianca e azzurra', color: '#6fb7ff' },
|
||||
{ id: 'arancio', name: 'Arancione', color: '#f08a2c' },
|
||||
{ id: 'viola', name: 'Viola e argento', color: '#9a5ad8' },
|
||||
];
|
||||
export const carImage = (id, big = false) => `assets/closeups/micro/${id}${big ? '-grande' : ''}.png`;
|
||||
// Dove stanno le macchinine nella scelta: due file da tre, al centro del parcheggio.
|
||||
export const choiceAt = i => [160 + (i % 3) * 160, 132 + Math.floor(i / 3) * 88];
|
||||
export function pick(c, i = c.choice) {
|
||||
if (c.step !== 'choose' || !CARS[i]) return false;
|
||||
const mine = CARS[i].id;
|
||||
c.colors = { player: mine, cpu: mine === 'blu' ? 'rossa' : 'blu' };
|
||||
c.step = 'aim'; c.t = 0; c.aimLocked = false; // il clic che sceglie non deve fissare anche la mira
|
||||
return true;
|
||||
}
|
||||
export function choose(c, i) {
|
||||
if (c.step !== 'choose' || !Number.isFinite(i)) return false;
|
||||
c.choice = (i + CARS.length) % CARS.length; return true;
|
||||
}
|
||||
const carUnder = (x, y) => CARS.findIndex((_, i) => { const [cx, cy] = choiceAt(i); return Math.abs(x - cx) < 44 && Math.abs(y - cy) < 30; });
|
||||
|
||||
export function newMicro(seed = Date.now() >>> 0, def = {}) {
|
||||
const level = LEVELS[def.level] ? def.level : 'seria', track = TRACK;
|
||||
const c = { step: 'aim', t: 0, seed, level, skill: LEVELS[level], current: 'player', power: 0.5, angle: 0,
|
||||
const c = { step: 'choose', choice: 0, colors: null, t: 0, seed, level, skill: LEVELS[level], current: 'player', power: 0.5, angle: 0,
|
||||
holding: false, holdTime: 0, accumulator: 0, events: [], track, laps: LAPS, flicks: { player: 0, cpu: 0 },
|
||||
line: null, trail: [], returns: [], before: null, plan: null, visual: { time: 0 } };
|
||||
// In griglia: Andrea all'esterno, il Chiaru all'interno, poco prima del traguardo.
|
||||
c.cars = { player: newCar(track, 'player', 18, -11), cpu: newCar(track, 'cpu', 18, 11) };
|
||||
c.angle = c.cars.player.heading;
|
||||
// Si parte scegliendo la macchinina, se non è già data (`def.car`).
|
||||
if (def.car) pick(c, CARS.findIndex(x => x.id === def.car));
|
||||
return c;
|
||||
}
|
||||
|
||||
@@ -285,7 +314,10 @@ export function aimAt(c, x, y) {
|
||||
if (Math.hypot(x - car.x, y - car.y) < CAR.r) return false;
|
||||
c.angle = Math.atan2(y - car.y, x - car.x); return true;
|
||||
}
|
||||
export const aimScreen = (c, [x, y]) => x >= 0 && x <= 640 && y >= 24 && y <= 360 && aimAt(c, x, y);
|
||||
export function aimScreen(c, [x, y]) {
|
||||
if (c.step === 'choose') { const i = carUnder(x, y); return i >= 0 && choose(c, i); }
|
||||
return x >= 0 && x <= 640 && y >= 24 && y <= 360 && aimAt(c, x, y);
|
||||
}
|
||||
export function nudge(c, dir, fine = false) {
|
||||
if (!canThrow(c) || c.holding || !Number.isFinite(dir)) return false;
|
||||
c.angle += dir * (fine ? 0.004 : 0.03); return true;
|
||||
@@ -294,8 +326,9 @@ export function setPower(c, value) {
|
||||
if (!canThrow(c) || c.holding || !Number.isFinite(value)) return false;
|
||||
c.power = clamp(value, 0, 1); return true;
|
||||
}
|
||||
export function shoot(c) { return canThrow(c) && !c.holding && strike(c, 'player', c.angle, c.power); }
|
||||
export function shoot(c) { return c.step === 'choose' ? pick(c) : canThrow(c) && !c.holding && strike(c, 'player', c.angle, c.power); }
|
||||
export function turn(c, dir, owner, fine = false) {
|
||||
if (c.step === 'choose') { choose(c, c.choice + dir); return false; } // nella scelta frecce e pulsanti cambiano macchinina
|
||||
if (!canThrow(c) || c.holding || c.turn) return false;
|
||||
c.turn = { dir, owner, fine, time: 0 }; c.angle += dir * (fine ? 0.004 : 0.03);
|
||||
c.aimLocked = true; return true;
|
||||
@@ -311,10 +344,11 @@ export function key(c, key, down, fine = false) {
|
||||
return true;
|
||||
}
|
||||
export function press(c, pointerId) {
|
||||
if (c.step === 'choose') return pick(c);
|
||||
if (!canThrow(c) || c.holding) return false;
|
||||
c.turn = null; c.pointerId = pointerId; c.holdDelay = pointerId === undefined ? 0 : LONG_PRESS;
|
||||
c.previousPower = c.power; c.holding = true; c.charging = false; c.holdTime = 0;
|
||||
if (!c.holdDelay) c.power = 0;
|
||||
// Premuto, la forza parte da zero e sale finché non si lascia (Andrea, 29 ottobre): come il dito che si carica.
|
||||
c.turn = null; c.pointerId = pointerId; c.holdDelay = 0;
|
||||
c.previousPower = c.power; c.holding = true; c.charging = false; c.holdTime = 0; c.power = 0;
|
||||
return true;
|
||||
}
|
||||
export function cancel(c, pointerId) {
|
||||
@@ -325,7 +359,7 @@ export function cancel(c, pointerId) {
|
||||
}
|
||||
export function release(c, pointerId) {
|
||||
if (c.pointerId !== pointerId || !c.holding) return false;
|
||||
if (c.holdTime < Math.max(0.14, c.holdDelay)) return cancel(c, pointerId); // il tocco mira soltanto
|
||||
if (c.holdTime < TAP) return cancel(c, pointerId); // il tocco secco mira soltanto
|
||||
const accompagne = (c.overHold ?? 0) > ACCOMPAGNA;
|
||||
c.holding = c.charging = false; c.overHold = 0;
|
||||
strike(c, 'player', c.angle, c.power);
|
||||
@@ -346,7 +380,11 @@ export function guide(c) {
|
||||
return { x: car.x + ux * length, y: car.y + uy * length, length, out };
|
||||
}
|
||||
|
||||
// Il pulsante del pannello vale anche nella scelta della macchinina.
|
||||
export const canPress = c => canThrow(c) || c.step === 'choose';
|
||||
export const canAdjust = canPress;
|
||||
export function button(c) {
|
||||
if (c.step === 'choose') return 'Scegli';
|
||||
if (c.step === 'result') return 'Finita';
|
||||
if (c.step === 'rolling' || c.step === 'settle') return 'In movimento…';
|
||||
return c.current === 'cpu' ? 'Spinge il Chiaru…' : 'Spingi';
|
||||
@@ -354,6 +392,7 @@ export function button(c) {
|
||||
// Quanta pista manca al traguardo, in percentuale, per il tabellone.
|
||||
export const done = (c, who) => clamp(c.cars[who].progress / (c.laps * c.track.length), 0, 1);
|
||||
export function status(c) {
|
||||
if (c.step === 'choose') return `Scegli la macchinina: ${CARS[c.choice].name}. Tocca quella che vuoi, o frecce e Scegli.`;
|
||||
const where = `Andrea ${Math.round(done(c, 'player') * 100)}%, Chiaru ${Math.round(done(c, 'cpu') * 100)}% del giro.`;
|
||||
if (c.step === 'result') return `${where} ${c.result.winner === 'player' ? 'Hai battuto il Chiaru!' : c.result.winner === 'cpu' ? 'Ha vinto il Chiaru.' : 'Arrivati pari.'}`;
|
||||
if (c.step === 'rolling' || c.step === 'settle') return `${where} ${c.line ?? ''}`.trim();
|
||||
|
||||
Reference in New Issue
Block a user