Lucciole, finestre che si accendono di sera, rondini, cipressi al vento e dissolvenza fra le scene
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ApqNBvNbNCwXqR2RLo8QJh
This commit is contained in:
@@ -374,6 +374,7 @@ export class Game {
|
||||
go(scene, at, face) {
|
||||
if (!this.story.scenes[scene]) throw new Error('Scena sconosciuta: ' + scene);
|
||||
this.state.scene = scene;
|
||||
this.enteredAt = this.time; // per gli effetti che cominciano all'ingresso (le finestre che si accendono)
|
||||
[this.state.x, this.state.y] = at ?? this.scene.entry;
|
||||
this.state.facing = FACING[face] ?? this.state.facing;
|
||||
this.path = [];
|
||||
|
||||
+58
-2
@@ -145,6 +145,8 @@ export function render(ctx, game, { hover, spots, debug, time = performance.now(
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
ctx.clearRect(0, 0, WIDTH, HEIGHT);
|
||||
if (bg) ctx.drawImage(bg, 0, 0, WIDTH, HEIGHT);
|
||||
// Gli effetti che muovono pezzi di sfondo (i cipressi al vento) vanno subito sopra lo sfondo, sotto tutto il resto.
|
||||
drawEffects(ctx, game, time, true);
|
||||
for (const shape of scene.art ?? []) drawShape(ctx, shape);
|
||||
// Una forma può avere la sua condizione (`when`): la chiavetta nella griglia sparisce quando la si prende.
|
||||
// I primi piani (`top`) invece vanno sopra a tutto, anche al buio e alle candele: si disegnano dopo.
|
||||
@@ -290,6 +292,58 @@ export const EFFECTS = {
|
||||
ctx.fillStyle = e.fill;
|
||||
for (const [x, y, w, h] of e.rects) closed ? ctx.fillRect(x, y + Math.floor(h / 2), w, 1) : ctx.fillRect(x, y, w, h);
|
||||
},
|
||||
// Lucciole di sera: puntini gialli che vagano piano e si accendono e si spengono.
|
||||
fireflies(ctx, e, time) {
|
||||
const [ax, ay, aw, ah] = e.area;
|
||||
for (let i = 0; i < (e.count ?? 8); i++) {
|
||||
const t = time / 1000, glow = Math.sin(t * (1.3 + hash(i) * 1.2) + i * 2);
|
||||
if (glow < 0.15) continue;
|
||||
const x = ax + aw * (0.5 + 0.45 * Math.sin(t * 0.21 + i * 2.3) * Math.cos(t * 0.13 + i)), y = ay + ah * (0.5 + 0.45 * Math.sin(t * 0.17 + i * 1.7));
|
||||
ctx.fillStyle = `rgba(255, 240, 120, ${0.25 * glow})`;
|
||||
ctx.fillRect(Math.round(x) - 1, Math.round(y) - 1, 3, 3);
|
||||
ctx.fillStyle = `rgba(230, 255, 140, ${glow})`;
|
||||
ctx.fillRect(Math.round(x), Math.round(y), 1, 1);
|
||||
}
|
||||
},
|
||||
// Le finestre che si accendono di sera, una dopo l'altra, appena si entra nella scena.
|
||||
windows(ctx, e, time, game) {
|
||||
const since = ((game.time ?? 0) - (game.enteredAt ?? 0)) * 1000;
|
||||
e.rects.forEach(([x, y, w, h], i) => {
|
||||
if (since < 400 + hash(i * 7 + 3) * (e.over ?? 3500)) return;
|
||||
ctx.fillStyle = 'rgba(255, 196, 100, 0.72)';
|
||||
ctx.fillRect(x, y, w, h);
|
||||
ctx.fillStyle = 'rgba(255, 236, 170, 0.5)';
|
||||
ctx.fillRect(x + 1, y + 1, Math.max(1, w - 2), Math.max(1, Math.floor(h / 3)));
|
||||
});
|
||||
},
|
||||
// Rondini: ogni tanto un gruppetto attraversa il cielo, da destra a sinistra.
|
||||
birds(ctx, e, time) {
|
||||
const [ax, ay, aw, ah] = e.area, every = e.every ?? 9000, t = (time % every) / every, run = Math.floor(time / every);
|
||||
if (t > 0.45) return;
|
||||
const k = t / 0.45;
|
||||
for (let i = 0; i < (e.count ?? 3); i++) {
|
||||
const x = Math.round(ax + aw - k * (aw + 40) + i * 9 + hash(run * 5 + i) * 10);
|
||||
const y = Math.round(ay + hash(run * 3 + i) * ah + Math.sin(k * 12 + i) * 3);
|
||||
const up = Math.floor(time / 120 + i) % 2;
|
||||
ctx.fillStyle = '#1e1a24';
|
||||
ctx.fillRect(x, y, 2, 1);
|
||||
ctx.fillRect(x - 2, y - up, 2, 1);
|
||||
ctx.fillRect(x + 2, y - up, 2, 1);
|
||||
}
|
||||
},
|
||||
// Alberi al vento (i cipressi): un pezzo di sfondo ridisegnato inclinato appena, più in cima che alla base.
|
||||
sway(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()) {
|
||||
const a = Math.sin(time / (e.speed ?? 900) + i * 1.3) * (e.amount ?? 1.6);
|
||||
for (let r = 0; r < h; r += 2) {
|
||||
const dx = Math.round(a * (1 - r / h));
|
||||
if (dx) ctx.drawImage(bg, x * k, (y + r) * k, w * k, 2 * k, x + dx, y + r, w, 2);
|
||||
}
|
||||
}
|
||||
},
|
||||
// Lampioni: un alone caldo che si accende (di solito solo di sera, con `phase`).
|
||||
lamps(ctx, e, time) {
|
||||
ctx.save();
|
||||
@@ -305,8 +359,10 @@ export const EFFECTS = {
|
||||
ctx.restore();
|
||||
},
|
||||
};
|
||||
function drawEffects(ctx, game, time) {
|
||||
for (const e of game.scene.effects ?? []) if (onNow(e, game)) EFFECTS[e.type]?.(ctx, e, time);
|
||||
const BACKGROUND_EFFECTS = new Set(['sway']);
|
||||
function drawEffects(ctx, game, time, background = false) {
|
||||
for (const e of game.scene.effects ?? [])
|
||||
if (BACKGROUND_EFFECTS.has(e.type) === background && onNow(e, game)) EFFECTS[e.type]?.(ctx, e, time, game);
|
||||
}
|
||||
|
||||
// Le scene buie (`shade`: il velo scuro sopra tutto, Andrea compreso) e le fiammelle (`lights`: candele accese).
|
||||
|
||||
Reference in New Issue
Block a user