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:
@@ -97,6 +97,26 @@ bad_swap_bounce :: (t: f32) -> f32 {
|
||||
BADSWAP_LUNGE_AMP * (1.0 - spring(u))
|
||||
}
|
||||
|
||||
// Per-column fall stagger (P17.2): within the fall window, each column starts its
|
||||
// drop at a small BOUNDED delay so a refilled/collapsed row pours in as a cascade
|
||||
// instead of every gem snapping down in one flat lockstep row. Column `col` waits
|
||||
// FALL_STAGGER_MAX * col/(BOARD_COLS-1) of the window, then falls over the
|
||||
// remaining `1 - FALL_STAGGER_MAX`, so the LAST column lands EXACTLY at t==1 and
|
||||
// every earlier column lands strictly before it — no gem is ever left mid-air when
|
||||
// the segment ends (the seam to the next round / settled board stays invisible).
|
||||
// Returns the column's LOCAL 0..1 progress; render_fall feeds it through
|
||||
// ease_in_cubic so each column still accelerates under gravity within its window.
|
||||
// `tests/easing.sx` pins f(0)=0, f(1)=1, monotonicity, and the cascade ordering.
|
||||
FALL_STAGGER_MAX :f32: 0.30;
|
||||
fall_stagger_t :: (t: f32, col: s64) -> f32 {
|
||||
delay := FALL_STAGGER_MAX * (cast(f32) col / cast(f32) (BOARD_COLS - 1));
|
||||
window := 1.0 - FALL_STAGGER_MAX;
|
||||
lt := (t - delay) / window;
|
||||
if lt <= 0.0 { return 0.0; }
|
||||
if lt >= 1.0 { return 1.0; }
|
||||
lt
|
||||
}
|
||||
|
||||
// One recorded cascade round. `before` is the board at the round's start (the
|
||||
// swapped board for round 0, the previous round's `after` otherwise — never has
|
||||
// holes). `matched` flags the cells cleared this round (they scale out). `src`
|
||||
|
||||
Reference in New Issue
Block a user