GP di Fortezza: guida a un dito col telefono (premuto è gas, lo swipe indica dove andare sullo schermo; Codex) e il casco di Tozzino alla Damon Hill (Andrea)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GiECdCPptNRwbVzjzHbohi
This commit is contained in:
+21
-10
@@ -3,7 +3,7 @@
|
||||
// la planimetria generale 1:500 che ha mandato Andrea (`assets/raw/fortezza-planimetria.png`), schiacciata nel
|
||||
// formato del gioco (640x360): x = 90 + (x0 - 215)·0,7, y = 20 + (y0 - 42)·0,49.
|
||||
//
|
||||
// Si tiene premuto per il gas (mouse, dito, Spazio o ↑), si sterza con ← → (o trascinando di lato col dito, o coi
|
||||
// Si tiene premuto per il gas (mouse, dito, Spazio o ↑), si sterza con ← → (o indicando la direzione con uno swipe, o coi
|
||||
// pulsanti), ↓ frena. Sulla pista: acceleratori, buche (andandoci forte si casca) e lattine di miscela da raccogliere.
|
||||
// Fuori strada c'è l'erba che frena, e poi la paglia: chi ci arriva forte si ferma.
|
||||
|
||||
@@ -29,6 +29,7 @@ export const LAPS = 3, STEP = 2, ROAD = 9, VERGE = 15, COUNTDOWN = 3, FIXED_STEP
|
||||
export const INTRO = { each: 4, ride: 1.8, from: 110, after: 1 };
|
||||
// Sterzo (rad/s a velocità piena di sterzo), freno, rallentamento senza gas, e quanto si scivola di lato in curva.
|
||||
export const TURN = 3.4, BRAKE = 150, COAST = 45, GRIP = 9, SLIDE = 0.5;
|
||||
export const SWIPE = { dead: 10, reach: 60, gain: 2.6 };
|
||||
export const BOOST = { speed: 1.35, time: 1.2 }, CAN = { time: 1.6, respawn: 6 }, HOLE = { fast: 45, out: 1.1 };
|
||||
const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
|
||||
const wrapAngle = a => Math.atan2(Math.sin(a), Math.cos(a));
|
||||
@@ -150,7 +151,7 @@ export function newGara(seed = Date.now() >>> 0, def = {}) {
|
||||
if (!riders.some(r => r.id === 'andrea')) throw new Error('Nella gara manca Andrea');
|
||||
for (const r of riders) { r.grid = r.s; r.shown = false; }
|
||||
return { step: 'intro', t: 0, age: 0, seed, level, skill, riders, holding: false, braking: false, keys: { left: false, right: false, gas: new Set(), brake: false },
|
||||
pointer: null, toggle: false, brakeButton: false, drag: 0, buttons: 0, anchor: null,
|
||||
pointer: null, toggle: false, brakeButton: false, drag: 0, buttons: 0, anchor: null, finger: null,
|
||||
power: 0, accumulator: 0, events: [], result: null, order: riders.map(r => r.id), taken: {} };
|
||||
}
|
||||
export const player = c => c.riders.find(r => r.id === 'andrea');
|
||||
@@ -167,7 +168,7 @@ export const setPower = () => false;
|
||||
function sync(c) {
|
||||
c.holding = c.keys.gas.size > 0 || c.pointer !== null || c.toggle;
|
||||
c.braking = c.keys.brake || c.brakeButton;
|
||||
if (c.pointer === null) c.drag = 0;
|
||||
if (c.pointer === null) { c.drag = 0; c.anchor = null; c.finger = null; }
|
||||
}
|
||||
// Il primo tocco (o tasto) salta la presentazione, senza dare gas.
|
||||
export function press(c, id = 'press') {
|
||||
@@ -209,12 +210,14 @@ function place(r, s, shown) {
|
||||
export const presenting = c => c.step === 'intro' ? c.riders[Math.floor(c.t / INTRO.each)] ?? null : null;
|
||||
// Il pulsante Gas del pannello: un tocco lo accende, un altro lo spegne (per chi non può tenere premuto).
|
||||
export function shoot(c) { if (!canThrow(c)) return false; if (c.step === 'intro') return nextIntro(c); c.toggle = !c.toggle; sync(c); return true; }
|
||||
// Il dito o il mouse premuto sulla scena: quanto ci si sposta di lato da dove si è premuto è lo sterzo. Il mouse che
|
||||
// passa senza premere, o col gas dato da tastiera o dal pannello, non sterza.
|
||||
export function aimScreen(c, [x], id = 'press') {
|
||||
if (!Number.isFinite(x)) return false;
|
||||
if (c.pointer === null) c.anchor = x;
|
||||
else if (c.pointer === id) c.drag = clamp((x - c.anchor) / 28, -1, 1);
|
||||
// Lo swipe indica dove andare sullo schermo. L'origine segue il dito oltre i 60 px.
|
||||
export function aimScreen(c, [x, y], id = 'press') {
|
||||
if (!Number.isFinite(x) || !Number.isFinite(y)) return false;
|
||||
if (c.pointer !== null && c.pointer !== id) return false;
|
||||
if (c.pointer === null || !c.anchor) c.anchor = [x, y];
|
||||
c.finger = [x, y];
|
||||
const dx = x - c.anchor[0], dy = y - c.anchor[1], distance = Math.hypot(dx, dy);
|
||||
if (distance > SWIPE.reach) c.anchor = [x - dx * SWIPE.reach / distance, y - dy * SWIPE.reach / distance];
|
||||
return false;
|
||||
}
|
||||
// La tastiera: ← → sterzano, ↑ Spazio e Invio sono il gas, ↓ il freno; finché si tengono giù.
|
||||
@@ -233,7 +236,15 @@ export function key(c, name, down) {
|
||||
// I pulsanti del pannello tenuti premuti: Sterza (-1, 0, 1) e Frena.
|
||||
export function steerButton(c, dir) { c.buttons = dir; return true; }
|
||||
export function brakeButton(c, down) { c.brakeButton = down; sync(c); return true; }
|
||||
export const steering = c => clamp((c.keys.right ? 1 : 0) - (c.keys.left ? 1 : 0) + c.buttons + c.drag, -1, 1);
|
||||
export function steering(c) {
|
||||
c.drag = 0;
|
||||
if (c.pointer !== null && c.anchor && c.finger) {
|
||||
const dx = c.finger[0] - c.anchor[0], dy = c.finger[1] - c.anchor[1];
|
||||
// Si ricalcola anche col dito fermo: il motorino intanto cambia direzione.
|
||||
if (Math.hypot(dx, dy) >= SWIPE.dead) c.drag = clamp(wrapAngle(Math.atan2(dy, dx) - player(c).a) * SWIPE.gain, -1, 1);
|
||||
}
|
||||
return clamp((c.keys.right ? 1 : 0) - (c.keys.left ? 1 : 0) + c.buttons + c.drag, -1, 1);
|
||||
}
|
||||
// La distanza davanti, sul giro, da s a un punto della pista (sempre fra 0 e la lunghezza del giro).
|
||||
export const ahead = (from, to) => ((((to - from) % TRACK.length) + TRACK.length) % TRACK.length);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user