All'Ingorgo Andrea ha la sua birra (foglio di Codex): camminando la tiene davanti al petto, parlando pure, e fermo alza il bicchiere schiumante a tempo con la folla (Andrea)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GiECd9RWGMKV7n3K1mdy8T
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"image": "andrea-birra.png",
|
||||
"height": 120,
|
||||
"frames": {
|
||||
"walk_1": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 68,
|
||||
"h": 114,
|
||||
"ax": 40.2,
|
||||
"ay": 114
|
||||
},
|
||||
"walk_2": {
|
||||
"x": 70,
|
||||
"y": 0,
|
||||
"w": 41,
|
||||
"h": 114,
|
||||
"ax": 20.7,
|
||||
"ay": 114
|
||||
},
|
||||
"walk_3": {
|
||||
"x": 113,
|
||||
"y": 0,
|
||||
"w": 67,
|
||||
"h": 114,
|
||||
"ax": 38.4,
|
||||
"ay": 114
|
||||
},
|
||||
"walk_4": {
|
||||
"x": 182,
|
||||
"y": 0,
|
||||
"w": 46,
|
||||
"h": 114,
|
||||
"ax": 25.3,
|
||||
"ay": 114
|
||||
},
|
||||
"cheer_1": {
|
||||
"x": 230,
|
||||
"y": 0,
|
||||
"w": 51,
|
||||
"h": 133,
|
||||
"ax": 21.1,
|
||||
"ay": 133
|
||||
},
|
||||
"cheer_2": {
|
||||
"x": 283,
|
||||
"y": 0,
|
||||
"w": 55,
|
||||
"h": 130,
|
||||
"ax": 24.5,
|
||||
"ay": 130
|
||||
},
|
||||
"cheer_3": {
|
||||
"x": 340,
|
||||
"y": 0,
|
||||
"w": 62,
|
||||
"h": 130,
|
||||
"ax": 23.8,
|
||||
"ay": 130
|
||||
},
|
||||
"talk": {
|
||||
"x": 404,
|
||||
"y": 0,
|
||||
"w": 58,
|
||||
"h": 120,
|
||||
"ax": 21.7,
|
||||
"ay": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 93 KiB |
+12
-1
@@ -179,7 +179,8 @@ export function render(ctx, game, { hover, spots, debug, time = performance.now(
|
||||
for (const shape of art) if (!shape.top) drawShape(ctx, shape);
|
||||
// Andrea e i personaggi della scena, dal più lontano al più vicino.
|
||||
const andrea = sprites.get('andrea');
|
||||
const drawAndreaNow = () => andrea ? drawSprite(ctx, andrea, game.pose(), s.x, s.y, game.scaleAt(s.y), s.facing)
|
||||
const party = festa(game, time), drawAndreaNow = () => party ? drawSprite(ctx, party.sheet, party.pose, s.x, s.y, game.scaleAt(s.y), s.facing)
|
||||
: andrea ? drawSprite(ctx, andrea, game.pose(), s.x, s.y, game.scaleAt(s.y), s.facing)
|
||||
: drawAndrea(ctx, s.x, s.y, game.scaleAt(s.y), s.facing, game.walking ? game.stride / 6 : null);
|
||||
// Durante il risveglio si guarda dagli occhi di Andrea: lui non si vede.
|
||||
const pov = game.closeup && game.story.closeups?.[game.closeup.id]?.type === 'risveglio';
|
||||
@@ -765,6 +766,16 @@ export const EFFECTS = {
|
||||
ctx.restore();
|
||||
},
|
||||
};
|
||||
// All'Ingorgo Andrea ha la sua birra (Andrea, 31 ottobre): camminando la tiene davanti al petto, parlando pure; fermo
|
||||
// alza il braccio col bicchiere e lo muove a tempo con la folla. Prendere e voltarsi restano quelli di sempre.
|
||||
const CHEER = ['cheer_1', 'cheer_2', 'cheer_1', 'cheer_3'];
|
||||
export function festa(game, time) {
|
||||
const sheet = sprites.get('andrea_birra'), band = (game.scene.effects ?? []).find(e => e.type === 'crowd' && onNow(e, game));
|
||||
if (!sheet || !band) return null;
|
||||
const pose = game.pose(), beat = Math.floor(time / 60000 * (band.bpm ?? 120)) % CHEER.length;
|
||||
const mine = pose === 'stand' ? CHEER[beat] : pose;
|
||||
return sheet.atlas.frames[mine] ? { sheet, pose: mine } : null;
|
||||
}
|
||||
// Andrea dentro la folla dell'Ingorgo (Andrea, 31 ottobre: «sembra di volare fra le persone»): sopra di lui, dalla
|
||||
// vita in giù, si ridisegna la gente dello sfondo che gli sta davanti. A strisce come l'effetto `crowd`, con lo stesso
|
||||
// sobbalzo a tempo (così le teste davanti saltano con le altre) e il bordo in alto a teste, mai dritto.
|
||||
|
||||
@@ -531,6 +531,7 @@ export const story = {
|
||||
// Andrea col pallone, per «Fai due tiri» (foglio di Codex dal suo sprite): non parla, lo disegna basket-render.
|
||||
andrea_basket: { name: 'Andrea', sprite: 'assets/characters/andrea-basket.json' },
|
||||
andrea_pesca: { name: 'Andrea', sprite: 'assets/characters/andrea-pesca.json' },
|
||||
andrea_birra: { name: 'Andrea', sprite: 'assets/characters/andrea-birra.json' }, // all'Ingorgo, con la birra
|
||||
// Quattro ragazzi inventati (sprite di Codex, idea di Andrea del 27 ottobre): nessuna persona reale.
|
||||
pescatori: { name: 'I ragazzi delle canne', color: '#b8f08a', sprite: 'assets/characters/pescatori.json' },
|
||||
// La gente della Smarronata del 1993 (Andrea, 31 ottobre): tutti inventati, vestiti come nei fotogrammi del video.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import { chromium } from 'playwright';
|
||||
import { staticServer } from './helpers.mjs';
|
||||
const server = await staticServer();
|
||||
const browser = await chromium.launch({ args: ['--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader'] });
|
||||
const page = await browser.newPage({ viewport: { width: 1280, height: 860 } });
|
||||
await page.goto(`http://127.0.0.1:${server.port}/`);
|
||||
await page.click('#splash'); await page.click('#new-game'); await page.click('#rione [data-rione="campomigliaio"]'); await page.click('#skip-intro');
|
||||
for (const [scene, at] of JSON.parse(process.env.SPOTS)) {
|
||||
await page.evaluate(async ([scene, at]) => {
|
||||
const { settle } = await import('/tests/helpers.mjs');
|
||||
settle(game); game.state.flags.ingorgo = true;
|
||||
game.go(scene, at, 'right'); settle(game);
|
||||
}, [scene, at]);
|
||||
await page.waitForTimeout(1500);
|
||||
await page.screenshot({ path: `${process.env.S}/folla-${scene}-${at[1]}.png`, clip: { x: 98, y: 60, width: 1084, height: 610 } });
|
||||
}
|
||||
await browser.close(); server.kill();
|
||||
@@ -168,6 +168,16 @@ test('le musiche e gli sfondi della festa esistono', () => {
|
||||
for (const f of files) assert.ok(existsSync(new URL('../' + f, import.meta.url)), `manca ${f}`);
|
||||
});
|
||||
|
||||
test('all\'Ingorgo Andrea ha la birra: il foglio coi passi, il braccio alzato a tempo e la battuta', async () => {
|
||||
const { readFileSync } = await import('node:fs');
|
||||
const atlas = JSON.parse(readFileSync(new URL('../assets/characters/andrea-birra.json', import.meta.url)));
|
||||
for (const f of ['walk_1', 'walk_2', 'walk_3', 'walk_4', 'cheer_1', 'cheer_2', 'cheer_3', 'talk']) assert.ok(atlas.frames[f], f);
|
||||
assert.equal(story.characters.andrea_birra.sprite, 'assets/characters/andrea-birra.json');
|
||||
const { festa } = await import('../src/engine/render.js');
|
||||
const g = new Game(story); g.go('piazza'); settle(g);
|
||||
assert.equal(festa(g, 0), null, 'senza la festa (e senza il foglio caricato) Andrea è quello di sempre');
|
||||
});
|
||||
|
||||
test('alla festa Andrea sta dentro la folla: dalla vita in giù la gente dello sfondo gli passa davanti', async () => {
|
||||
const { crowdFront } = await import('../src/engine/render.js');
|
||||
const g = new Game(story); g.go('piazzetta', [330, 320]); settle(g);
|
||||
|
||||
Reference in New Issue
Block a user