P10.3: wire the SFX bank to game events (sx / iOS)
Drive event-appropriate cues from the existing System Sound Services bank, purely additively — no board/score/move state is read or written and every call stays inline-if-OS==.ios guarded. board_view.sx (move-commit path): a committed gesture now plays the swap slide cue for any swipe intent (legal or the reverted ping-back); a legal move adds the match pop on its first clearing round; a multi-round chain adds the escalating cascade cue keyed to the recorded AnimMove depth (mv.rounds.len), kept distinct from the match pop so a single clear is never doubled. An illegal swap plays only the swap cue. main.sx (frame loop): the win/lose stinger fires EXACTLY ONCE, edge-triggered on the frame the banner comes up — the level has settled won/lost and any in-flight cascade has finished animating. Status is read-only from the model; a restart re-arms the edge for a fresh win/lose. audio.sx: each play_* method logs a per-cue NSLog line at play time so the ordering is observable via `log show`; cascade_cue_name maps the clamped combo index to a stable literal (literals only — the string→NSString bridge needs NUL-terminated bytes).
This commit is contained in:
17
main.sx
17
main.sx
@@ -80,6 +80,12 @@ g_motion : *GemMotion = null;
|
||||
// fire the landing squash-bounce on the exact frame a move settles.
|
||||
g_anim_prev_active : bool = false;
|
||||
|
||||
// Tracks whether the win/lose banner was up last frame, so the frame loop fires
|
||||
// the win/lose stinger (P10.3) EXACTLY ONCE — on the frame the level settles
|
||||
// terminal and any final cascade has played out — instead of replaying it every
|
||||
// frame the banner is up. Re-armed when a restart reopens the level.
|
||||
g_banner_prev_up : bool = false;
|
||||
|
||||
// Rebuilt each frame inside the pipeline's arena; carries the current safe-area
|
||||
// insets so the grid stays inside the notch / home-indicator region.
|
||||
build_ui :: () -> View {
|
||||
@@ -196,6 +202,17 @@ frame :: () {
|
||||
}
|
||||
}
|
||||
|
||||
// Win/lose stinger (P10.3): edge-trigger on the banner coming up — the level
|
||||
// has settled won/lost AND any in-flight cascade has finished animating — so
|
||||
// the stinger plays once as the banner appears, never every frame it is up.
|
||||
// Status is read-only from the model (mirrors BoardView.banner_up); a restart
|
||||
// reopens the level, dropping the edge so a fresh win/lose re-fires.
|
||||
banner_now := level_status(g_board) != .in_progress and (g_anim == null or !g_anim.active);
|
||||
if banner_now and !g_banner_prev_up {
|
||||
if level_status(g_board) == .won { sfx_win(); } else { sfx_lose(); }
|
||||
}
|
||||
g_banner_prev_up = banner_now;
|
||||
|
||||
inline if OS == .ios {
|
||||
// Lazy-attach Metal once -[SxAppDelegate didFinishLaunching:] has
|
||||
// installed the SxMetalView and its bounds have been measured; both can
|
||||
|
||||
Reference in New Issue
Block a user