Ombre delle fronde al Bosco ai Frati, bandiere del campeggio al vento, fascio di luce nella Pieve; nel viale semi e foglioline verdi invece delle foglie d'autunno
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ApqNBvNbNCwXqR2RLo8QJh
This commit is contained in:
+43
-1
@@ -411,6 +411,48 @@ export const EFFECTS = {
|
|||||||
lc.globalCompositeOperation = 'source-over';
|
lc.globalCompositeOperation = 'source-over';
|
||||||
ctx.drawImage(layer, 0, 0);
|
ctx.drawImage(layer, 0, 0);
|
||||||
},
|
},
|
||||||
|
// Le ombre delle fronde sul terreno: macchie scure e chiare che ondeggiano piano col vento, come sotto un albero.
|
||||||
|
leafshadow(ctx, e, time) {
|
||||||
|
const [ax, ay, aw, ah] = e.area, t = time / 1000;
|
||||||
|
for (let i = 0; i < (e.count ?? 14); i++) {
|
||||||
|
const bx = ax + hash(i * 7) * aw, by = ay + hash(i * 13) * ah, r = 3 + hash(i * 3) * (e.size ?? 6);
|
||||||
|
const x = bx + Math.sin(t * 0.9 + i) * 2 + Math.sin(t * 0.37 + i * 2) * 2, y = by + Math.sin(t * 0.7 + i * 3) * 1;
|
||||||
|
ctx.fillStyle = i % 3 ? 'rgba(30, 20, 45, 0.24)' : 'rgba(255, 235, 170, 0.18)';
|
||||||
|
for (let dy = -r; dy <= r; dy += 1) {
|
||||||
|
const half = Math.round(Math.sqrt(r * r - dy * dy) * 1.6);
|
||||||
|
ctx.fillRect(Math.round(x - half), Math.round(y + dy / 2), half * 2, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Una bandiera dipinta nello sfondo che sventola: a strisce verticali che salgono e scendono, ferme dalla parte
|
||||||
|
// dell'asta (`pole`: 'left' o 'right') e sempre più mosse verso il lembo libero.
|
||||||
|
cloth(ctx, e, time, game) {
|
||||||
|
const bg = backgrounds.get(game.scene.background);
|
||||||
|
if (!bg) return;
|
||||||
|
const k = bg.width / WIDTH;
|
||||||
|
for (const [i, [x, y, w, h]] of e.rects.entries()) {
|
||||||
|
for (let c = 0; c < w; c++) {
|
||||||
|
const free = e.pole === 'left' ? c / w : 1 - c / w;
|
||||||
|
const dy = Math.sin(time / 260 - free * 5 + i) * free * (e.amount ?? 2.2);
|
||||||
|
ctx.drawImage(bg, (x + c) * k, y * k, k, h * k, x + c, y + dy, 1, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Un fascio di luce da una finestra: un cono chiaro che sfuma fino al pavimento, appena pulsante.
|
||||||
|
beam(ctx, e, time) {
|
||||||
|
const [[x1, y1], [x2, y2], [x3, y3], [x4, y4]] = e.poly, pulse = 0.85 + 0.15 * Math.sin(time / 2300);
|
||||||
|
const g = ctx.createLinearGradient(x1, y1, (x3 + x4) / 2, (y3 + y4) / 2);
|
||||||
|
g.addColorStop(0, `rgba(255, 236, 180, ${0.42 * pulse})`);
|
||||||
|
g.addColorStop(1, 'rgba(255, 236, 180, 0)');
|
||||||
|
ctx.save();
|
||||||
|
ctx.globalCompositeOperation = 'lighter';
|
||||||
|
ctx.fillStyle = g;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.lineTo(x3, y3); ctx.lineTo(x4, y4);
|
||||||
|
ctx.closePath();
|
||||||
|
ctx.fill();
|
||||||
|
ctx.restore();
|
||||||
|
},
|
||||||
// Lampioni: un alone caldo che si accende (di solito solo di sera, con `phase`).
|
// Lampioni: un alone caldo che si accende (di solito solo di sera, con `phase`).
|
||||||
lamps(ctx, e, time) {
|
lamps(ctx, e, time) {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
@@ -426,7 +468,7 @@ export const EFFECTS = {
|
|||||||
ctx.restore();
|
ctx.restore();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const BACKGROUND_EFFECTS = new Set(['sway', 'clouds']);
|
const BACKGROUND_EFFECTS = new Set(['sway', 'clouds', 'cloth', 'leafshadow']);
|
||||||
function drawEffects(ctx, game, time, background = false) {
|
function drawEffects(ctx, game, time, background = false) {
|
||||||
for (const e of game.scene.effects ?? [])
|
for (const e of game.scene.effects ?? [])
|
||||||
if (BACKGROUND_EFFECTS.has(e.type) === background && onNow(e, game)) EFFECTS[e.type]?.(ctx, e, time, game);
|
if (BACKGROUND_EFFECTS.has(e.type) === background && onNow(e, game)) EFFECTS[e.type]?.(ctx, e, time, game);
|
||||||
|
|||||||
+4
-1
@@ -522,6 +522,7 @@ export const story = {
|
|||||||
name: 'Dentro la Pieve',
|
name: 'Dentro la Pieve',
|
||||||
map: [56, 39],
|
map: [56, 39],
|
||||||
background: 'assets/scenes/pieve-interno.png',
|
background: 'assets/scenes/pieve-interno.png',
|
||||||
|
effects: [{ type: 'beam', phase: ['pomeriggio', 'tramonto'], poly: [[22, 122], [32, 118], [250, 360], [150, 360]] }, { type: 'dust', phase: ['pomeriggio', 'tramonto'], area: [60, 200, 90, 110], count: 9 }],
|
||||||
// Penombra, e le sei candele dell'altare accese (Andrea, 24 ottobre).
|
// Penombra, e le sei candele dell'altare accese (Andrea, 24 ottobre).
|
||||||
indoor: true,
|
indoor: true,
|
||||||
shade: 'rgba(14, 8, 24, 0.62)',
|
shade: 'rgba(14, 8, 24, 0.62)',
|
||||||
@@ -695,6 +696,7 @@ export const story = {
|
|||||||
name: 'Ingresso del campeggio',
|
name: 'Ingresso del campeggio',
|
||||||
map: [12, 84],
|
map: [12, 84],
|
||||||
background: 'assets/scenes/campeggio.png',
|
background: 'assets/scenes/campeggio.png',
|
||||||
|
effects: [{ type: 'cloth', pole: 'right', rects: [[28, 108, 26, 44], [84, 92, 36, 72], [229, 104, 34, 30], [548, 92, 58, 64]] }],
|
||||||
walk: [[150, 360], [165, 262], [420, 266], [640, 286], [640, 360]],
|
walk: [[150, 360], [165, 262], [420, 266], [640, 286], [640, 360]],
|
||||||
depth: [[262, 0.6], [360, 1.15]],
|
depth: [[262, 0.6], [360, 1.15]],
|
||||||
entry: [200, 345],
|
entry: [200, 345],
|
||||||
@@ -726,6 +728,7 @@ export const story = {
|
|||||||
name: 'Bosco ai Frati',
|
name: 'Bosco ai Frati',
|
||||||
map: [12, 96],
|
map: [12, 96],
|
||||||
background: 'assets/scenes/bosco-ai-frati.png',
|
background: 'assets/scenes/bosco-ai-frati.png',
|
||||||
|
effects: [{ type: 'leafshadow', phase: ['pomeriggio', 'tramonto'], area: [0, 296, 230, 50], count: 16 }],
|
||||||
walk: [[0, 304], [100, 298], [480, 292], [640, 300], [640, 360], [0, 360]],
|
walk: [[0, 304], [100, 298], [480, 292], [640, 300], [640, 360], [0, 360]],
|
||||||
depth: [[292, 0.78], [360, 1.1]],
|
depth: [[292, 0.78], [360, 1.1]],
|
||||||
entry: [320, 345],
|
entry: [320, 345],
|
||||||
@@ -1123,7 +1126,7 @@ export const story = {
|
|||||||
name: 'Via Provinciale, il viale alberato',
|
name: 'Via Provinciale, il viale alberato',
|
||||||
map: [72, 68],
|
map: [72, 68],
|
||||||
background: 'assets/scenes/provinciale-viale.png',
|
background: 'assets/scenes/provinciale-viale.png',
|
||||||
effects: [{ type: 'clouds', area: [300, 10, 220, 120], count: 2 }, { type: 'leaves', area: [20, 40, 360, 250], count: 7 }],
|
effects: [{ type: 'clouds', area: [300, 10, 220, 120], count: 2 }, { type: 'leaves', area: [20, 40, 360, 250], count: 4, colors: ['#a8c44e', '#efe8c8', '#7fa83a'] }],
|
||||||
walk: [[0, 360], [0, 330], [400, 232], [462, 232], [620, 360]],
|
walk: [[0, 360], [0, 330], [400, 232], [462, 232], [620, 360]],
|
||||||
depth: [[232, 0.4], [360, 1.7]],
|
depth: [[232, 0.4], [360, 1.7]],
|
||||||
entry: [300, 350],
|
entry: [300, 350],
|
||||||
|
|||||||
Reference in New Issue
Block a user