P4.4: selection highlight + score/moves HUD (sx, iOS sim)

Tap a gem to select it: BoardView hit-tests the touch to a grid cell and
draws a bright rim + translucent fill over it; tapping the same cell clears
the selection, tapping another moves it, tapping off-board clears it.
Selection only — no swap (that's P5). The HUD renders the live score and
remaining moves (out of the move limit) in the Lato font on a translucent
card above the grid.

The touch→cell geometry is factored into a pure BoardLayout (no GL/stb
imports) that BoardView composes and P5 will reuse for swap endpoints.
tests/hit_test.sx locks point_to_cell as the exact inverse of cell_frame
(every cell center round-trips; off-board taps reject) — headless because
BoardLayout pulls no C imports. goldens/p4_hud.png captures the scene after
a real idb tap at (201,437)pt: the HUD plus a yellow selection rim on the
red gem at cell (col 4, row 3).
This commit is contained in:
swipelab
2026-06-05 00:00:48 +03:00
parent 3cd1ef1585
commit 9ed98c73d2
7 changed files with 237 additions and 25 deletions

View File

@@ -40,10 +40,14 @@ g_metal_gpu : *MetalGPU = null;
g_board : *Board = null;
g_assets : *BoardAssets = null;
// Current cell selection (P4.4). Heap-allocated so it survives BoardView's
// per-frame rebuild; a tap hit-tests a cell and toggles this.
g_sel : *BoardSelection = null;
// 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 {
BoardView.{ board = g_board, assets = g_assets, safe = g_safe_insets }
BoardView.{ board = g_board, assets = g_assets, sel = g_sel, safe = g_safe_insets }
}
frame :: () {
@@ -137,6 +141,9 @@ main :: () -> void {
g_assets.init();
g_assets.load(g_pipeline.gpu);
g_sel = xx context.allocator.alloc(size_of(BoardSelection));
g_sel.init();
g_pipeline.set_body(closure(build_ui));
g_plat.run_frame_loop(closure(frame));