All chapters · Chapter 6/9

The wall

Starting

Forty bricks, and not one of them written by hand.

const spawnBrick = useSpawn(Brick);
for (let row = 0; row < BRICK_ROWS; row++) {
    for (let col = 0; col < BRICK_COLS; col++) {
        spawnBrick({ row, col });
    }
}

Two loops, one grid

A loop walks a list. Two nested loops walk a grid: for every row, every column. Five rows by eight columns, forty passes, forty bricks.

And the position comes from arithmetic, not a table:

const x = MARGIN_X + col * (BRICK_W + GAP_X);
const y = TOP + row * (BRICK_H + GAP_Y);

Start at the margin, then advance one brick plus one gap per column. Change BRICK_COLS to 12 and the wall rebuilds itself. With forty hand-written positions, changing the layout would be an afternoon.

The colour comes from the row too:

tint: getColor(ROW_COLORS[row]),

ROW_COLORS is a list of five colours and ROW_COLORS[row] picks the matching one: [0] is the first, [1] the second. Lists start counting at zero, always, in every language you're going to meet.

A second file

Something new here: there are two tabs above the editor. bricks.ts is a separate file, and the main one pulls it in with:

import { BRICK_COLS, BRICK_ROWS, Brick } from './bricks';

It isn't ceremony, it's the natural moment. The old file did one thing; now there are two subjects (the match and the bricks) and each fits whole in your head. One file per subject is what keeps a game editable three months later.

useSpawn: an object of its own for each brick

const spawnBrick = useSpawn(Brick);
spawnBrick({ row: 0, col: 3 });

Up to now you were making loose sprites in the scene. useSpawn prepares a brick maker, and every call to it gives birth to an object with an identity of its own, bundling everything Brick registers: its sprite, its state, its loops. Whatever you pass between the parentheses reaches Brick as its argument.

Right now it looks like a wrapper with no payoff. Next chapter it's what lets you delete one specific brick without touching the other thirty-nine.

What exactly does a `for` do?
for (let col = 0; col < 8; col++) {
    // ...
}

Three parts separated by semicolons:

  1. let col = 0: start counting at zero.
  2. col < 8: keep going while this is true.
  3. col++: and after each pass, add one.

So the block runs with col equal to 0, 1, 2, 3, 4, 5, 6 and 7. Eight passes. At 8 the condition fails and it stops.

When you put a for inside another, the inner one runs its whole cycle for every pass of the outer one. Five outer × eight inner = forty.

Your turn

Try BRICK_ROWS = 8. Try BRICK_COLS = 4 (note the wall comes up short: the brick width is fixed, so there's a gap on the right).

And change the colours in ROW_COLORS. Five strings, any CSS colour.

The ball still sails straight through the bricks. That's next.