P17.2: organic fall — per-column stagger (cascade pour)

render_fall now offsets each COLUMN's drop START by a small bounded delay
(fall_stagger_t) so a refilled/collapsed row pours in as a left-to-right cascade
instead of every gem snapping down in one flat lockstep row. Column col waits
FALL_STAGGER_MAX (0.30) * col/7 of the fall window, then falls over the remaining
1 - 0.30, with that local progress fed through ease_in_cubic so each column still
accelerates under gravity within its own window.

Bounded by construction: the last column lands EXACTLY at t=1 and every earlier
column strictly before it, so no gem is ever left mid-air at the segment end — the
seam to the next round / settled board stays invisible and move.final is untouched.

FALL_ANIM_DUR (0.22s) and the timeline helpers (phase/total/cascade_rounds_started)
are unchanged, so the per-round cascade-cue timing snapshots don't churn and live
per-round audio is unaffected. Render-only — no board.sx model change.

tests/easing.sx pins fall_stagger_t: f(0)=0, f(1)=1 across all columns (no gem
unlanded), per-column monotonicity, and the mid-fall cascade ordering (each later
column strictly behind the one before). tests/anim_plan.sx (final==model,
contiguity) stays green.

Golden goldens/p17_stagger.png: M3TE_FX=11 (depth-5 cascade, seed 1337) pinned at
M3TE_ANIM_TIME=1.91 — round 4 refills columns 2-7 by one cell each, so the top row
reads as a left-to-right staircase (vs the pre-stagger flat row in p17_fall.png).
This commit is contained in:
swipelab
2026-06-06 11:35:36 +03:00
parent 8d4e7acd2b
commit 02d856275c
6 changed files with 98 additions and 3 deletions

View File

@@ -531,16 +531,19 @@ BoardView :: struct {
// Fall segment: every gem of the round's settled board accelerates under
// gravity from its source row (above the board for refills) down to its
// destination cell. ease_in_cubic pins f(1)=1, so each gem lands exactly on
// its cell and the seam to the next round / settled board stays invisible.
// destination cell. Each COLUMN's drop starts at a small staggered delay
// (fall_stagger_t) so a refilled row pours in as a cascade rather than a flat
// lockstep row; ease_in_cubic pins each column's f(1)=1, and fall_stagger_t
// guarantees every column reaches 1 by t==1, so each gem lands exactly on its
// cell and the seam to the next round / settled board stays invisible.
render_fall :: (self: *BoardView, ctx: *RenderContext, rd: *AnimRound, inset: f32, dim: f32, t: f32) {
te := ease_in_cubic(t);
for 0..BOARD_CELLS: (i) {
g := rd.after[i];
if g == .empty { continue; }
col := i % BOARD_COLS;
drow := i / BOARD_COLS;
src := rd.src[i];
te := ease_in_cubic(fall_stagger_t(t, col));
cur_row := cast(f32) src + (cast(f32) drow - cast(f32) src) * te;
gf := self.gem_frame(cast(f32) col, cur_row, inset, dim);
self.draw_gem(ctx, gf, cast(s64) g);