Fixed timestep, free render
Physics accumulate in 16.67 ms slices, so a 120 Hz phone renders twice as smoothly without doubling ball speed. Rendering is decoupled and interpolated by state, never by elapsed time.
Fixed 60 Hz physics, swept AABB collision with penetration-depth resolution, and a paddle that maps contact point to bounce angle. Clear all 32 bricks before the third ball drops.
How the ball, paddle and grid negotiate contact
Physics accumulate in 16.67 ms slices, so a 120 Hz phone renders twice as smoothly without doubling ball speed. Rendering is decoupled and interpolated by state, never by elapsed time.
Each 60 Hz step moves the 3 px ball in halves and tests collisions between them. That stops a fast ball from tunnelling through a 20 px brick row or a 10 px paddle.
The ball's bounding box is tested against every live brick; the closest overlap wins, and the axis with the smaller penetration decides the reflected component — vertical overlap flips dy, horizontal flips dx.
After a hit the ball is pushed out along the collision normal and the brick is flagged dead before the loop breaks — no brick is consumed twice, and adjacent cells resolve on the next sub-step.
Paddle contact maps −1…1 across the 60 px face to ±60° from vertical, plus a nudge from paddle momentum. Velocity is then renormalized to 3.44 px/step, so hits never inflate or stall the speed.
|dy| keeps it recoverable.dx.