P18.1: organic combine — anticipation pop on match clear (sx, iOS sim)
Sharpen clear_pop_scale from a plain pop-then-shrink into a candy pop in three beats over its local 0..1: a tiny anticipation squash dip (~8% below rest), a snappy overshoot to ~1.40x via P15.1's ease_out_back, then an accelerating collapse to nothing (ease_in_quad). Endpoints stay locked (t=0 -> 1.0 rest, t=1 -> 0.0 gone), so the seam to the model board is clean and M3TE_ANIM_TIME=0 still reproduces the rest board; the particle burst / score popup compose on top unchanged. render_clear and CLEAR_ANIM_DUR are untouched, so cascade-cue timing snapshots don't churn and the model is unchanged. tests/gem_pose.sx now pins the new envelope (locked rest endpoints, the anticipation dip, the overshoot, the monotonic post-peak collapse) with its expected snapshot updated. goldens/p18_pop.png: new mid-clear pop golden at the overshoot peak (M3TE_FX=3 M3TE_ANIM_TIME=0.21). goldens/p6_fx_match.png refreshed for the new pop shape (same scene at its documented 0.22). README documents P18.1.
This commit is contained in:
35
gem_anim.sx
35
gem_anim.sx
@@ -76,22 +76,39 @@ land_squash :: (tl: f32) -> f32 {
|
||||
}
|
||||
|
||||
// --- Clear pop ---------------------------------------------------------------
|
||||
// The matched-gem clear: a snappy outward pop then a collapse to nothing over its
|
||||
// local 0..1, so the clear reads as a satisfying candy pop rather than a plain
|
||||
// shrink. A fast rise to a bigger overshoot makes the snap read; the soft
|
||||
// particle burst / score popup (board_fx.sx) compose on top.
|
||||
CLEAR_POP_A :f32: 0.34; // overshoot height above resting scale
|
||||
CLEAR_POP_RISE :f32: 0.18; // fraction of the window spent rising to the peak
|
||||
// The matched-gem clear, shaped as a candy pop in three beats over its local
|
||||
// 0..1: a tiny anticipation squash dip (a "gather" just below rest), a snappy
|
||||
// overshoot up to the peak via P15.1's ease_out_back, then an accelerating
|
||||
// collapse to nothing. Endpoints are LOCKED — t==0 -> 1.0 (rest) and t==1 -> 0.0
|
||||
// (gone) — so the seam to the model board stays clean; the soft particle burst /
|
||||
// score popup (board_fx.sx) compose on top.
|
||||
CLEAR_DIP_T :f32: 0.16; // fraction of the window spent on the anticipation dip
|
||||
CLEAR_DIP_A :f32: 0.08; // how far the gem compresses below rest before popping
|
||||
CLEAR_POP_RISE :f32: 0.52; // window fraction at which the overshoot peak is reached
|
||||
CLEAR_POP_A :f32: 0.36; // overshoot height above resting scale
|
||||
|
||||
clear_pop_scale :: (t: f32) -> f32 {
|
||||
if t <= 0.0 { return 1.0; }
|
||||
if t >= 1.0 { return 0.0; }
|
||||
if t < CLEAR_POP_RISE {
|
||||
return 1.0 + CLEAR_POP_A * (t / CLEAR_POP_RISE);
|
||||
if t < CLEAR_DIP_T {
|
||||
// Anticipation gather: sin(PI*u) is 0 at both ends, so t==0 stays exactly
|
||||
// at rest and the dip hands off to the rise at rest — a brief squash, not
|
||||
// a step.
|
||||
u := t / CLEAR_DIP_T;
|
||||
return 1.0 - CLEAR_DIP_A * sin(PI * u);
|
||||
}
|
||||
if t < CLEAR_POP_RISE {
|
||||
// Snap up to the peak: ease_out_back rises from rest, shoots a touch past
|
||||
// 1+A, then eases back to exactly 1+A at the seam (its locked f(1)=1), so
|
||||
// the maximum is a single clean overshoot with no second reversal.
|
||||
u := (t - CLEAR_DIP_T) / (CLEAR_POP_RISE - CLEAR_DIP_T);
|
||||
return 1.0 + CLEAR_POP_A * ease_out_back(u);
|
||||
}
|
||||
// Collapse to nothing: accelerate the shrink from the peak so the gem vanishes
|
||||
// as the burst takes over. ease_in_quad pins the seam at the peak and t==1 at 0.
|
||||
peak := 1.0 + CLEAR_POP_A;
|
||||
u := (t - CLEAR_POP_RISE) / (1.0 - CLEAR_POP_RISE);
|
||||
peak * (1.0 - u * u)
|
||||
peak * (1.0 - ease_in_quad(u))
|
||||
}
|
||||
|
||||
// Live per-gem animation state, heap-allocated (like BoardAnim/BoardFx) so it
|
||||
|
||||
Reference in New Issue
Block a user