Il Regolo del futuro: alla SUPER SPECIAL un'esplosione a sorpresa apre la tavola futuristica (Orbita del Serpente, Ponte della Fortezza sopraelevato, Spira al Neon, Regolo mobile); si torna alla classica colpendo il Regolo dopo due giri per percorso (Codex)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GiECd9RWGMKV7n3K1mdy8T
This commit is contained in:
+83
-19
@@ -131,28 +131,92 @@ try {
|
||||
await page.screenshot({ path: `${out}/${name}-super.png` });
|
||||
const multi = await page.evaluate(async () => {
|
||||
window.pinballShot('super');
|
||||
const m = await import('/src/engine/flipper.js'); m.update(game.closeup, 0.25); m.update(game.closeup, 0.25);
|
||||
// Ferma solo la simulazione per fotografare le tre palline, prima che una possa scendere.
|
||||
window.pinballResume = game.update.bind(game); game.update = dt => { game.closeup.visual.time += dt; };
|
||||
return { balls: m.activeBalls(game.closeup).length, locks: game.closeup.locks.length, reserve: game.closeup.balls, time: game.closeup.visual.time };
|
||||
const m = await import('/src/engine/flipper.js'), c = game.closeup;
|
||||
window.pinballResume = game.update.bind(game); game.update = () => {};
|
||||
window.pinballClassic = structuredClone(c); window.pinballClassic.transform = null;
|
||||
(await import('/src/engine/render.js')).render(document.querySelector('#scene').getContext('2d'), game, { time: performance.now() });
|
||||
m.update(c, 0.25); m.update(c, 0.2);
|
||||
window.pinballExplosion = structuredClone(c);
|
||||
return { balls: m.activeBalls(c).length, locks: c.locks.length, reserve: c.balls };
|
||||
});
|
||||
assert.deepEqual({ balls: multi.balls, locks: multi.locks, reserve: multi.reserve }, { balls: 3, locks: 0, reserve: 5 });
|
||||
await page.waitForFunction(t => game.closeup.visual.time > t + 0.7, multi.time);
|
||||
assert.deepEqual(multi, { balls: 3, locks: 0, reserve: 5 });
|
||||
await page.screenshot({ path: `${out}/${name}-esplosione.png` });
|
||||
await page.evaluate(async () => {
|
||||
const m = await import('/src/engine/flipper.js');
|
||||
for (let i = 0; i < 6; i++) m.update(game.closeup, 0.25);
|
||||
});
|
||||
await page.screenshot({ path: `${out}/${name}-trasformazione.png` });
|
||||
await page.evaluate(async () => {
|
||||
const m = await import('/src/engine/flipper.js');
|
||||
for (let i = 0; i < 6; i++) m.update(game.closeup, 0.25);
|
||||
window.pinballFuture = structuredClone(game.closeup);
|
||||
});
|
||||
assert.equal(await page.evaluate(() => game.closeup.table), 'future');
|
||||
await page.screenshot({ path: `${out}/${name}-futuro.png` });
|
||||
await page.screenshot({ path: `${out}/${name}-multiball.png` });
|
||||
// L'arretrato grafico (vedi la memoria «effetti leggeri»): 150 fotogrammi disegnati di fila con tre palline e gli
|
||||
// effetti vivi, poi una lettura dei pixel che aspetta la grafica. Il flipper di Codex ne lasciava 4,2 s; deve
|
||||
// restare sotto il secondo e mezzo anche col rendering software di queste prove.
|
||||
const backlog = await page.evaluate(async () => {
|
||||
const m = await import('/src/engine/flipper.js'), r = await import('/src/engine/render.js'), c = game.closeup;
|
||||
const ctx = document.querySelector('#scene').getContext('2d');
|
||||
ctx.getImageData(0, 0, 4, 4); // si aspetta prima l'arretrato di tutta la prova fin qui
|
||||
for (let i = 0; i < 150; i++) { m.update(c, 1 / 60); r.render(ctx, game, { time: performance.now() }); }
|
||||
const t = performance.now(); ctx.getImageData(0, 0, 4, 4); return Math.round(performance.now() - t);
|
||||
// Anche nel nuovo campo: due dita indipendenti, i due Shift e la pausa vera dell'applicazione.
|
||||
if (mobile) {
|
||||
await touch('touchStart', [P(250, 200), P(400, 200)]);
|
||||
await page.waitForFunction(() => game.closeup.flippers.left.held.length && game.closeup.flippers.right.held.length);
|
||||
await touch('touchEnd', []);
|
||||
} else {
|
||||
await page.keyboard.down('ShiftLeft'); await page.keyboard.down('ShiftRight');
|
||||
await page.waitForFunction(() => game.closeup.flippers.left.held.length && game.closeup.flippers.right.held.length);
|
||||
}
|
||||
await page.evaluate(() => { game.update = window.pinballResume; });
|
||||
await page.click('#pause-button');
|
||||
const paused = await page.evaluate(() => ({ sim: game.closeup.sim, hits: game.closeup.future.hits, score: game.closeup.score }));
|
||||
await page.waitForTimeout(250);
|
||||
assert.deepEqual(await page.evaluate(() => ({ sim: game.closeup.sim, hits: game.closeup.future.hits, score: game.closeup.score })), paused);
|
||||
assert.ok(await page.evaluate(() => !game.closeup.flippers.left.held.length && !game.closeup.flippers.right.held.length));
|
||||
if (!mobile) { await page.keyboard.up('ShiftLeft'); await page.keyboard.up('ShiftRight'); }
|
||||
await page.click('#resume');
|
||||
await page.evaluate(() => { game.update = () => {}; Object.assign(game.closeup, structuredClone(window.pinballFuture)); });
|
||||
// Stessa lettura sincrona dei pixel per classico, detonazione/trasformazione e futuro. Si svuota prima
|
||||
// l'arretrato precedente; in gioco si riportano in alto solo le palline prossime alla buca per misurare
|
||||
// tutti i 150 fotogrammi con tre palline, senza finire accidentalmente sul campo classico.
|
||||
for (const mode of ['classico', 'esplosione', 'futuro']) {
|
||||
const backlog = await page.evaluate(async mode => {
|
||||
const m = await import('/src/engine/flipper.js'), r = await import('/src/engine/render.js'), c = game.closeup;
|
||||
Object.assign(c, structuredClone(mode === 'classico' ? window.pinballClassic : mode === 'esplosione' ? window.pinballExplosion : window.pinballFuture));
|
||||
const ctx = document.querySelector('#scene').getContext('2d');
|
||||
r.render(ctx, game, { time: performance.now() }); ctx.getImageData(0, 0, 4, 4);
|
||||
for (let i = 0; i < 150; i++) {
|
||||
if (mode !== 'esplosione') for (const [k, b] of m.activeBalls(c).entries()) {
|
||||
b.releaseAt = 0;
|
||||
if (b.y > 295) Object.assign(b, { x: 260 + k * 55, y: 200, vx: 20, vy: -150, ramp: null });
|
||||
}
|
||||
m.update(c, 1 / 60); r.render(ctx, game, { time: performance.now() });
|
||||
}
|
||||
const t = performance.now(); ctx.getImageData(0, 0, 4, 4); const ms = Math.round(performance.now() - t);
|
||||
if (mode === 'futuro' && c.table !== 'future') throw new Error('misura uscita dal futuro');
|
||||
return ms;
|
||||
}, mode);
|
||||
console.log(`${name}: arretrato grafico ${mode} dopo 150 fotogrammi ${backlog} ms`);
|
||||
assert.ok(backlog < 1500, `${mode}: arretrato grafico ${backlog} ms`);
|
||||
}
|
||||
// Percorsi veri fino al finale: la schermata mostra sigilli caricati e il bersaglio mobile da colpire.
|
||||
await page.evaluate(async () => {
|
||||
const m = await import('/src/engine/flipper.js'), c = game.closeup;
|
||||
Object.assign(c, structuredClone(window.pinballFuture));
|
||||
for (const b of c.extraBalls) b.releaseAt = c.sim + 1000;
|
||||
for (const id of ['orbita', 'ponte', 'spira']) for (let i = 0; i < 2; i++) window.pinballShot(id);
|
||||
});
|
||||
console.log(`${name}: arretrato grafico dopo 150 fotogrammi ${backlog} ms`);
|
||||
assert.ok(backlog < 1500, `arretrato grafico ${backlog} ms`);
|
||||
await page.waitForFunction(() => document.querySelector('#scene').style.backgroundImage.startsWith('url('), null, { timeout: 2000 }); // il mobile sullo sfondo CSS
|
||||
await page.evaluate(() => { game.update = window.pinballResume; delete window.pinballResume; delete window.pinballShot; });
|
||||
assert.deepEqual(await page.evaluate(() => game.closeup.future.hits), { orbita: 2, ponte: 2, spira: 2 });
|
||||
await page.screenshot({ path: `${out}/${name}-sigilli.png` });
|
||||
await page.evaluate(async () => {
|
||||
const m = await import('/src/engine/flipper.js'), c = game.closeup;
|
||||
Object.assign(c.ball, { x: 320 + Math.sin((c.sim + m.STEP) * 1.6) * 24, y: c.regolo.y + c.regolo.r + 4, vx: 0, vy: -250, ramp: null, contacts: [] });
|
||||
m.update(c, m.STEP);
|
||||
});
|
||||
assert.equal(await page.evaluate(() => game.closeup.table), 'classic');
|
||||
await page.evaluate(async () => {
|
||||
(await import('/src/engine/render.js')).render(document.querySelector('#scene').getContext('2d'), game, { time: performance.now() });
|
||||
const m = await import('/src/engine/flipper.js'); m.update(game.closeup, 0.25); m.update(game.closeup, 0.25);
|
||||
});
|
||||
await page.screenshot({ path: `${out}/${name}-ritorno.png` });
|
||||
await page.waitForFunction(() => document.querySelector('#scene').style.backgroundImage.startsWith('url('));
|
||||
await page.evaluate(() => { game.update = window.pinballResume; for (const key of ['pinballResume', 'pinballShot', 'pinballClassic', 'pinballExplosion', 'pinballFuture']) delete window[key]; });
|
||||
// Si consumano le palline rimaste, compresa quella vinta, per arrivare al risultato reale.
|
||||
const finalScore = await page.evaluate(async () => {
|
||||
const m = await import('/src/engine/flipper.js'), c = game.closeup;
|
||||
|
||||
Reference in New Issue
Block a user