Workshop › Puzzle Bobble-style Bubble Shooter › Step 5 of 31
Real bubbles pack like marbles in a box: every other row is shifted half a bubble to the right, so each bubble nests in the gap between the two above it. This is a hex grid, like a honeycomb. Rows get closer, and odd rows have one bubble less.
```js
const ROW_H = R * Math.sqrt(3) // rows overlap so the bubbles nest
const cols = (r) => (r % 2 === 0 ? COLS : COLS - 1)
const cellPos = (r, c) => ({ x: R + c * 2 * R + (r % 2) * R, y: TOP + R + r * ROW_H })
for (let c = 0; c < cols(r); c++) grid[r].push(r < 5 ? Math.floor(Math.random() * COLORS.length) : -1)
for (let c = 0; c < cols(r); c++) {
```r % 2 is the remainder of dividing by 2: 0 on even rows, 1 on odd rows. So odd rows get + R in x.ROW_H = R × √3, about 1.73 R instead of 2 R: a bubble and the two it rests on form an equilateral triangle with
sides 2R, whose height is 2R × √3 / 2.cols(r) is 10 on even rows and 9 on odd rows; the grid and the drawing use it instead of COLS.ROWS write ROW_H.cellPos write cols, and change cellPos as shown.reset and in draw, replace c < COLS with c < cols(r).Skills: Arrays and objects, Drawing on a canvas