fix: tetris collision detection — pieces now stack properly

Added 'blocked' signal that checks frozen grid cells below active piece.
Collision check branches on py to inspect the correct grid row (13-19).
Gravity only drops when not blocked. Lock triggers on blocked state.
Freeze writes piece into correct row based on py (7 rows supported).
Added grid rendering for rows 13-15 (total 7 visible frozen rows).
Build output: 84KB
This commit is contained in:
enzotar 2026-02-27 12:20:09 -08:00
parent 075c4a20fe
commit d9e0e31d1b

View file

@ -81,36 +81,77 @@ on keydown(ev) -> py = if gameOver then py else (if paused then py else (if ev.k
on keydown(ev) -> paused = if ev.key == "p" then (if paused then 0 else 1) else paused
-- ================================================================
-- LAYER 4: DERIVED SIGNALS — Gravity, lock, line clear
-- LAYER 4: DERIVED SIGNALS — Collision, gravity, lock, line clear
-- ================================================================
-- Collision detection signal: is the row BELOW the piece occupied?
-- For a standard piece (3 wide, 2 tall like T), the bottom cells are at py+1.
-- We check if grid row py+2 has any blocks at the piece's x positions.
-- `blocked` = 1 means can't move down, 0 means safe to drop.
--
-- Since grid rows are individual signals, we branch on py to check the right row.
-- Also blocked at the bottom wall (py >= 18 for standard pieces).
let blocked = 0
-- Check collision: at bottom wall OR frozen cells below
-- T/J/L/S/Z pieces: bottom at py+1, so check py+2
-- I piece: bottom at py+1, check py+2
-- Piece bottom row = py+1, next row down = py+2
every 33 -> blocked = if py > 17 then 1 else (if py == 17 then (if g19[px] > 0 then 1 else (if g19[px + 1] > 0 then 1 else 0)) else (if py == 16 then (if g18[px] > 0 then 1 else (if g18[px + 1] > 0 then 1 else 0)) else (if py == 15 then (if g17[px] > 0 then 1 else (if g17[px + 1] > 0 then 1 else 0)) else (if py == 14 then (if g16[px] > 0 then 1 else (if g16[px + 1] > 0 then 1 else 0)) else (if py == 13 then (if g15[px] > 0 then 1 else (if g15[px + 1] > 0 then 1 else 0)) else (if py == 12 then (if g14[px] > 0 then 1 else (if g14[px + 1] > 0 then 1 else 0)) else 0))))))
-- Gravity tick
every 33 -> gravityTick = if paused then gravityTick else (if gameOver then gravityTick else gravityTick + 1)
-- Auto-drop
every 33 -> py = if paused then py else (if gameOver then py else (if gravityTick > dropInterval then (if py < 18 then py + 1 else py) else py))
-- Auto-drop: only if NOT blocked
every 33 -> py = if paused then py else (if gameOver then py else (if blocked then py else (if gravityTick > dropInterval then (if py < 18 then py + 1 else py) else py)))
every 33 -> gravityTick = if gravityTick > dropInterval then 0 else gravityTick
-- Lock detection
every 33 -> lockTick = if py > 17 then lockTick + 1 else 0
-- Lock detection: start counting when blocked
every 33 -> lockTick = if blocked then lockTick + 1 else 0
-- Freeze piece into grid rows on lock (simplified: T, I, O, J, L, S, Z)
-- Row 18 cells
every 33 -> g18[px] = if lockTick == 3 then (if py > 17 then piece else g18[px]) else g18[px]
every 33 -> g18[px + 1] = if lockTick == 3 then (if py > 17 then piece else g18[px + 1]) else g18[px + 1]
every 33 -> g18[px + 2] = if lockTick == 3 then (if py > 17 then (if piece == 4 then g18[px + 2] else piece) else g18[px + 2]) else g18[px + 2]
-- ── Freeze piece into grid at py position on lock ──
-- The piece top-row cells go into row py, bottom-row cell into py+1
-- For T-piece: (px,py), (px+1,py), (px+2,py) and (px+1,py+1)
-- We write the top 3 cells into grid[py] and bottom cell into grid[py+1]
-- Row 17 cells (T-piece has cell at (px+1, py+1))
every 33 -> g17[px + 1] = if lockTick == 3 then (if py > 16 then (if piece == 6 then 6 else (if piece == 4 then 4 else g17[px + 1])) else g17[px + 1]) else g17[px + 1]
-- Freeze top cells into grid row py (for each possible py value)
-- Row 19
every 33 -> g19[px] = if lockTick == 3 then (if py == 19 then piece else g19[px]) else g19[px]
every 33 -> g19[px + 1] = if lockTick == 3 then (if py == 19 then piece else g19[px + 1]) else g19[px + 1]
every 33 -> g19[px + 2] = if lockTick == 3 then (if py == 19 then piece else g19[px + 2]) else g19[px + 2]
-- Row 18
every 33 -> g18[px] = if lockTick == 3 then (if py == 18 then piece else g18[px]) else g18[px]
every 33 -> g18[px + 1] = if lockTick == 3 then (if py == 18 then piece else g18[px + 1]) else g18[px + 1]
every 33 -> g18[px + 2] = if lockTick == 3 then (if py == 18 then piece else g18[px + 2]) else g18[px + 2]
-- Row 17
every 33 -> g17[px] = if lockTick == 3 then (if py == 17 then piece else g17[px]) else g17[px]
every 33 -> g17[px + 1] = if lockTick == 3 then (if py == 17 then piece else g17[px + 1]) else g17[px + 1]
every 33 -> g17[px + 2] = if lockTick == 3 then (if py == 17 then piece else g17[px + 2]) else g17[px + 2]
-- Row 16
every 33 -> g16[px] = if lockTick == 3 then (if py == 16 then piece else g16[px]) else g16[px]
every 33 -> g16[px + 1] = if lockTick == 3 then (if py == 16 then piece else g16[px + 1]) else g16[px + 1]
every 33 -> g16[px + 2] = if lockTick == 3 then (if py == 16 then piece else g16[px + 2]) else g16[px + 2]
-- Row 15
every 33 -> g15[px] = if lockTick == 3 then (if py == 15 then piece else g15[px]) else g15[px]
every 33 -> g15[px + 1] = if lockTick == 3 then (if py == 15 then piece else g15[px + 1]) else g15[px + 1]
every 33 -> g15[px + 2] = if lockTick == 3 then (if py == 15 then piece else g15[px + 2]) else g15[px + 2]
-- Row 14
every 33 -> g14[px] = if lockTick == 3 then (if py == 14 then piece else g14[px]) else g14[px]
every 33 -> g14[px + 1] = if lockTick == 3 then (if py == 14 then piece else g14[px + 1]) else g14[px + 1]
every 33 -> g14[px + 2] = if lockTick == 3 then (if py == 14 then piece else g14[px + 2]) else g14[px + 2]
-- Row 13
every 33 -> g13[px] = if lockTick == 3 then (if py == 13 then piece else g13[px]) else g13[px]
every 33 -> g13[px + 1] = if lockTick == 3 then (if py == 13 then piece else g13[px + 1]) else g13[px + 1]
every 33 -> g13[px + 2] = if lockTick == 3 then (if py == 13 then piece else g13[px + 2]) else g13[px + 2]
-- Row 17 freeze for py==17
every 33 -> g17[px] = if py == 17 then (if lockTick == 3 then piece else g17[px]) else g17[px]
every 33 -> g17[px + 2] = if py == 17 then (if lockTick == 3 then (if piece == 4 then g17[px + 2] else piece) else g17[px + 2]) else g17[px + 2]
-- Row 16 freeze for py==16
every 33 -> g16[px] = if py == 16 then (if lockTick == 3 then piece else g16[px]) else g16[px]
every 33 -> g16[px + 1] = if py == 16 then (if lockTick == 3 then piece else g16[px + 1]) else g16[px + 1]
every 33 -> g16[px + 2] = if py == 16 then (if lockTick == 3 then (if piece == 4 then g16[px + 2] else piece) else g16[px + 2]) else g16[px + 2]
-- Freeze T-piece bottom center cell into grid[py+1]
-- (T has a cell at px+1, py+1; also applicable to O, S, Z shapes)
every 33 -> g19[px + 1] = if lockTick == 3 then (if py == 18 then (if piece == 6 then 6 else g19[px + 1]) else g19[px + 1]) else g19[px + 1]
every 33 -> g18[px + 1] = if lockTick == 3 then (if py == 17 then (if piece == 6 then 6 else g18[px + 1]) else g18[px + 1]) else g18[px + 1]
every 33 -> g17[px + 1] = if lockTick == 3 then (if py == 16 then (if piece == 6 then 6 else g17[px + 1]) else g17[px + 1]) else g17[px + 1]
every 33 -> g16[px + 1] = if lockTick == 3 then (if py == 15 then (if piece == 6 then 6 else g16[px + 1]) else g16[px + 1]) else g16[px + 1]
every 33 -> g15[px + 1] = if lockTick == 3 then (if py == 14 then (if piece == 6 then 6 else g15[px + 1]) else g15[px + 1]) else g15[px + 1]
every 33 -> g14[px + 1] = if lockTick == 3 then (if py == 13 then (if piece == 6 then 6 else g14[px + 1]) else g14[px + 1]) else g14[px + 1]
-- Spawn new piece after lock
every 33 -> piece = if lockTick == 3 then nextPiece else piece
@ -124,18 +165,23 @@ every 33 -> score = if lockTick == 3 then score + 10 else score
every 33 -> score = if g19[0] > 0 then (if g19[2] > 0 then (if g19[4] > 0 then (if g19[6] > 0 then (if g19[8] > 0 then score + 100 else score) else score) else score) else score) else score
every 33 -> lines = if g19[0] > 0 then (if g19[2] > 0 then (if g19[4] > 0 then (if g19[6] > 0 then (if g19[8] > 0 then lines + 1 else lines) else lines) else lines) else lines) else lines
-- Shift rows down on clear
-- Shift rows down on clear: copy row 18 into row 19
every 33 -> g19[0] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[0] else g19[0]) else g19[0]) else g19[0]
every 33 -> g19[1] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[1] else g19[1]) else g19[1]) else g19[1]
every 33 -> g19[2] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[2] else g19[2]) else g19[2]) else g19[2]
every 33 -> g19[3] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[3] else g19[3]) else g19[3]) else g19[3]
every 33 -> g19[4] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[4] else g19[4]) else g19[4]) else g19[4]
every 33 -> g19[5] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[5] else g19[5]) else g19[5]) else g19[5]
every 33 -> g19[6] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[6] else g19[6]) else g19[6]) else g19[6]
every 33 -> g19[7] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[7] else g19[7]) else g19[7]) else g19[7]
every 33 -> g19[8] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[8] else g19[8]) else g19[8]) else g19[8]
every 33 -> g19[9] = if g19[0] > 0 then (if g19[4] > 0 then (if g19[8] > 0 then g18[9] else g19[9]) else g19[9]) else g19[9]
-- Level up
every 33 -> level = if lines > 0 then (lines / 10 + 1) else 1
every 33 -> dropInterval = if level > 9 then 3 else (27 - level * 3)
-- Game over
-- Game over: any cell in row 0 filled
every 33 -> gameOver = if g0[3] > 0 then 1 else (if g0[4] > 0 then 1 else (if g0[5] > 0 then 1 else gameOver))
-- ================================================================
@ -180,7 +226,19 @@ view tetris_game = column [
for k in [0,1,2,3,4,5,6,7,8,9] ->
column { style: "position:absolute; width:1px; height:600px; left:{k * 30}px; background:rgba(99,102,241,0.08)" } []
-- Frozen grid: row 16 (Layer 1 data -> Layer 5 UI)
-- Frozen grid: row 13 (Layer 1 data -> Layer 5 UI)
for c in [0,1,2,3,4,5,6,7,8,9] ->
column { style: "position:absolute; width:28px; height:28px; top:391px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g13[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
-- Frozen grid: row 14
for c in [0,1,2,3,4,5,6,7,8,9] ->
column { style: "position:absolute; width:28px; height:28px; top:421px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g14[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
-- Frozen grid: row 15
for c in [0,1,2,3,4,5,6,7,8,9] ->
column { style: "position:absolute; width:28px; height:28px; top:451px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g15[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []
-- Frozen grid: row 16
for c in [0,1,2,3,4,5,6,7,8,9] ->
column { style: "position:absolute; width:28px; height:28px; top:481px; left:{c * 30 + 1}px; border-radius:4px; background:linear-gradient(180deg,#a855f7,#7c3aed); opacity:{if g16[c] > 0 then 1 else 0}; transition:opacity 0.15s; box-shadow:0 0 8px rgba(168,85,247,0.4)" } []