# 17. Tutorial: Breakout

This chapter builds a complete game from an empty file: three lives, six rows of bricks,
three level layouts, a score, a high score, sound, and a title screen that plays itself.
Nothing is loaded from disk — the ball and the paddle are drawn from numbers in the
listing, and the wall, the HUD and the messages are characters written into the text grid.

This is what you are building:

![The finished game: a HUD line across the top, six rows of bricks, the ball resting on the paddle](images/breakout-game.png)

The finished listing is
[`examples/breakout/characters/breakout.bas`](../examples/breakout/characters/breakout.bas).
You do not need it to follow along, but it is the same program assembled, and it is worth
opening once you have your own running.

Run it with the SDL build:

```sh norun
$ ./build-akgl/basic examples/breakout/characters/breakout.bas
```

| Key | Does |
|---|---|
| left / right | move the paddle |
| space | start a game, then launch the ball |
| P | pause |
| Q or escape | quit |

## What you will do

- **[Step 1](#step-1-get-a-program-onto-the-screen)** — get a program onto the screen, and
  find out which build you need
- **[Step 2](#step-2-measure-the-screen)** — measure the screen and work the geometry out
  from what you measured
- **[Step 3](#step-3-declare-every-name-first)** — declare every name the program will use,
  before anything uses it
- **[Step 4](#step-4-make-the-ball-and-the-paddle)** — make the ball and the paddle out of
  sprite data
- **[Step 5](#step-5-build-the-brick-wall)** — build the brick wall out of characters, and
  keep a grid saying which bricks are still there
- **[Step 6](#step-6-write-the-main-loop)** — write the main loop and the frame pacing
- **[Step 7](#step-7-read-the-keyboard)** — read the keyboard without blocking
- **[Step 8](#step-8-move-the-paddle)** — move the paddle and keep it on the screen
- **[Step 9](#step-9-move-the-ball)** — move the ball and bounce it off the walls
- **[Step 10](#step-10-break-bricks)** — find out which brick the ball hit, and break it
- **[Step 11](#step-11-bounce-off-the-paddle)** — bounce off the paddle at an angle the
  player chooses
- **[Step 12](#step-12-draw-the-hud-and-the-messages)** — draw the HUD and the messages
- **[Step 13](#step-13-lives-levels-and-game-over)** — handle lives, levels and game over
- **[Step 14](#step-14-add-sound)** — add sound, on a machine that may not have any
- **[Step 15](#step-15-add-an-attract-mode)** — add a title screen that plays itself
- **[Step 16](#step-16-put-the-program-together)** — put the pieces in one file, in the
  right order

Each step is a piece you can type in and run. Work through them in order, and Step 16 is
where they become one program.

---

## Step 1: Get a program onto the screen

**Goal: a program that runs, and a build that can draw.**

A BASIC program here is a text file. Line numbers are optional, so a file is just
statements, one per line:

```basic
PRINT "HELLO"
END
```

```output
HELLO
```

Save that as `first.bas` and run it:

```sh norun
$ ./build/basic first.bas
```

There are two builds and the difference matters for this whole chapter. `./build/basic` is
the plain one: it reads and writes text and has **no graphics device, no sprites and no
sound**. `./build-akgl/basic` opens a window and has all three. A game needs the second.

Ask for something that needs a device and you get a refusal naming what is missing rather
than a crash:

```basic requires=noakgl
PRINT "BEFORE"
SPRITE 1, 1, 2
PRINT "AFTER"
```

```output
BEFORE
? 2 : RUNTIME ERROR SPRITE needs a sprite device and this runtime has none

```

That is worth seeing once, because it is how the finished game behaves if you start it
with the wrong build: it stops at the first graphics verb and tells you why.

For the rest of this chapter, run everything with `./build-akgl/basic`.

Two more things to know before writing anything longer.

**Every variable carries a type suffix.** `A#` is an integer, `A%` is a float, `A$` is a
string. There is no such thing as a plain `A` — a bare word is a label. This is different
from Commodore BASIC, where `A%` is the integer.

**`+` joins a string to a number.** `"SCORE " + 40` is `"SCORE 40"`, and `"" + N#` is how
you turn a number into a string. There is no `STR$`.

```basic
N# = 40
PRINT "SCORE " + N#
END
```

```output
SCORE 40
```

## Step 2: Measure the screen

**Goal: every position in the game derived from the window's real size, so the game fits
whatever window and font the player has.**

Do not guess the size of anything. Four functions tell you what you have:

| Call | Gives |
|---|---|
| `RGR(1)` | the window's width in pixels |
| `RGR(2)` | the window's height in pixels |
| `RGR(3)` | the width of one character cell, in pixels |
| `RGR(4)` | the height of one character cell |
| `RWINDOW(0)` | the text grid's height, in rows |
| `RWINDOW(1)` | the text grid's width, in columns |

Put them at the very top of the program:

```basic norun
SCW# = RGR(1)
SCH# = RGR(2)
CW# = RGR(3)
CH# = RGR(4)
COLS# = RWINDOW(1)
ROWS# = RWINDOW(0)
```

`RGR(1)` is first on purpose. It is the first statement in the program that needs a
graphics device, so on the wrong build this is the line that refuses, and it refuses
before anything else has happened.

Now derive the layout from those numbers rather than writing pixel positions down. The
wall is measured in **character cells**, because it is made of characters:

```basic norun
BRW# = 4
BCOLS# = 10
BROWS# = 6
BTOP# = 4
BLEFT# = (COLS# - (BRW# * BCOLS#)) / 2
```

A brick is four cells wide and there are ten of them, so the wall is forty cells across.
`BLEFT#` centres those forty in however many columns there turned out to be. `BTOP#` is
the row the wall starts on. Integer division truncates, which is exactly what a column
index wants.

The ball and the paddle are sprites, and **sprites are positioned in pixels**, so the play
area is measured in pixels:

```basic norun
TOPY# = 2 * CH#
MAXX# = SCW# - 8
PW# = 144
PY# = 528
LOSEY# = PY# + 32
PSPD# = 10
MSGROW# = 35
TITROW# = 20
```

`TOPY#` is the ceiling the ball bounces off, two rows down from the top so it clears the
HUD line. `MAXX#` is as far right as the ball can go — the window less the ball's own
eight pixels. `PW#` is the paddle's width and `PY#` the row of pixels it sits on.
`MSGROW#` and `TITROW#` are text rows, counted from the top, for messages.

**Cells and pixels are two different coordinate systems, and they meet in exactly one
place** — Step 5, where each brick's cell is turned into the rectangle `SOLID` registers.
Everywhere else, bricks are in cells and everything that moves is in pixels.

## Step 3: Declare every name first

**Goal: a subroutine that can hand an answer back to its caller.**

A `GOSUB` gets its own scope. That has one consequence you must design around:

- Assigning to a name that already exists **outside** the subroutine walks up and finds it.
  The change is visible to the caller.
- Assigning to a name that has **never been seen before** creates it inside the
  subroutine. It disappears at `RETURN`, and the caller reads zero — with no error and no
  warning of any kind.

So a subroutine cannot answer through a name it invented itself. Declare the names first,
at the top of the program, and then any routine can write to them:

```basic
X# = 0
GOSUB SUBA
PRINT "THE CALLER SEES " + X#
END

LABEL SUBA
X# = 99
RETURN
```

```output
THE CALLER SEES 99
```

Take `X# = 0` off the top of that program and it prints `0`.

This is why the game opens with a block that names everything before the first `GOSUB`.
Arrays go in the same block. Here is the start of it — the names the later steps refer to
most; [Step 16](#step-16-put-the-program-together) has the finished block, all 66 of them,
and you can paste that in now if you would rather not come back to it:

```basic norun
DIM BR#(60)
DIM SB#(63)
DIM SP#(63)
DIM LAY$(6)
DIM BSG$(6)

SCORE# = 0
HIGH# = 0
LIVES# = 3
LEVEL# = 1
LEFTN# = 0
BSPD# = 4
STATE# = 0
HELD# = 0
PX# = 0
BX# = 0
BY# = 0
BVX# = 0
BVY# = 0
HIT# = 0
BI# = 0
BR2# = 0
```

`HIT#`, `BI#` and `BR2#` are the three the rule is really about: they are how the
collision test in Step 10 answers the routine that called it.

**`DIM` belongs at the top and nowhere else.** An array declared inside a `GOSUB` or a
loop takes storage from a pool of 4096 elements that is never given back, so a `DIM` that
runs repeatedly will eventually end the program:

```basic
X# = 0
FOR T# = 1 TO 6000
  GOSUB SUBA
NEXT T#
PRINT "OK " + X#
END

LABEL SUBA
DIM LOC#(4)
LOC#(0) = 1
X# = X# + LOC#(0)
RETURN
```

```output
? 8 : RUNTIME ERROR Array of 4 elements does not fit in the 0 remaining value slots

```

A plain number costs nothing, though, so you can create as many of those inside a routine
as you like:

```basic
X# = 0
FOR T# = 1 TO 20000
  GOSUB SUBA
NEXT T#
PRINT "OK " + X#
END

LABEL SUBA
LOC# = 1
X# = X# + LOC#
RETURN
```

```output
OK 20000
```

Twenty thousand calls, each creating a local, and the program is fine. The rule that
survives is the narrow one: **`DIM` at the top, never inside anything.**

### Two rules about writing expressions

Both apply everywhere in this chapter, so they are worth fixing in your fingers now.

**Parenthesise any expression that mixes `+` and `-`.** Write `(A# - B#) + C#`, not
`A# - B# + C#`:

```basic
A# = 10
B# = 3
C# = 2
PRINT (A# - B#) + C#
END
```

```output
9
```

**Parenthesise a condition that uses more than one `AND` or `OR`.** Write
`IF (A# = 1 AND B# = 2) AND C# = 3 THEN`:

```basic
A# = 1
B# = 2
C# = 3
IF (A# = 1 AND B# = 2) AND C# = 3 THEN PRINT "ALL THREE"
END
```

```output
ALL THREE
```

Both habits are free, and both are being made unnecessary: the parser's additive
precedence is [`TODO.md` §6 item 35](../TODO.md) and the second `AND` is item 36 beside
it. Once those land, the plain forms will mean what they look like they mean, and
parentheses you wrote in the meantime will still be correct.

## Step 4: Make the ball and the paddle

**Goal: two sprites on the screen, in the right places.**

A sprite is a 24-by-21 pattern of pixels. `SPRSAV` loads one from an **integer array of 63
numbers**: three bytes per row, twenty-one rows, most significant bit on the left. A bit
that is 1 draws; a bit that is 0 is transparent.

```text
       byte 0            byte 1            byte 2
  7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0
  ^ column 0                                        ^ column 23
```

The ball is an 8-by-8 disc drawn in the **top-left corner** of the pattern. Putting it
there means the sprite's position and the ball's pixel rectangle are the same thing, so no
part of the game needs to add an offset to work out where the ball actually is:

```text
  . . # # # # . .    60
  . # # # # # # .   126
  # # # # # # # #   255
```

The paddle is a solid bar, 24 wide and 6 deep — the full width of a sprite. `SPRITE`'s
x-expand flag doubles it to 48 pixels, and three of those laid end to end make one
144-pixel paddle with no seam.

```basic requires=akgl screenshot=breakout-paddle size=240x120
DIM SB#(63)
DIM SP#(63)
I# = 0
D# = 0
FOR I# = 0 TO 62
  SB#(I#) = 0
  SP#(I#) = 0
NEXT I#
FOR I# = 0 TO 7
  READ D#
  SB#(I# * 3) = D#
NEXT I#
FOR I# = 0 TO 17
  SP#(I#) = 255
NEXT I#
SPRSAV SB#, 1
SPRSAV SP#, 2
SPRSAV SP#, 3
SPRSAV SP#, 4
SPRITE 1, 1, 2
SPRITE 2, 1, 15, 0, 1, 0
SPRITE 3, 1, 15, 0, 1, 0
SPRITE 4, 1, 15, 0, 1, 0
MOVSPR 1, 108, 40
MOVSPR 2, 48, 80
MOVSPR 3, 96, 80
MOVSPR 4, 144, 80

DATA 60, 126, 255, 255, 255, 255, 126, 60
```

![The ball above three paddle segments meeting with no seam](images/breakout-paddle.png)

Read that from the middle. `SPRSAV SB#, 1` installs the ball's pattern into slot 1.
`SPRITE 1, 1, 2` turns slot 1 on in colour 2. `SPRITE 2, 1, 15, 0, 1, 0` turns slot 2 on
in colour 15 with the fourth argument after the colour — the x-expand flag — set to 1.
`MOVSPR` puts a sprite at a pixel position, measured from its top-left corner.

The finished game writes the same 63 numbers out as `DATA`, one row per line, with the
bit pattern drawn in a comment beside each, and loads them in a routine called once at
startup. [Step 16](#step-16-put-the-program-together) has that routine and both patterns
in full; the loops above are the same two patterns spelled shorter so the figure fits on a
page.

Moving the four sprites is one routine, and every coordinate is worked out into a variable
before it is passed:

```basic norun
LABEL SHOWSPR
MOVSPR 1, BX#, BY#
MOVSPR 2, PX#, PY#
X2# = PX# + 48
MOVSPR 3, X2#, PY#
X3# = PX# + 96
MOVSPR 4, X3#, PY#
RETURN
```

**Do not write `MOVSPR 3, PX# + 48, PY#`.** `MOVSPR` reads a leading sign as *move by this
much* rather than *move to here*, and an expression beginning with a sign is the relative
form. Computing into `X2#` first says exactly what you mean. See
[Chapter 8](08-sprites.md#showing-and-moving).

## Step 5: Build the brick wall

**Goal: a wall on the screen, and a grid in memory saying which bricks are still standing.**

Two things are needed and they are separate: the *state* (which of the sixty bricks are
alive) and the *picture* (what the player sees). Keep them in step by always redrawing the
row you just changed.

### The layouts

A level is six strings of ten characters, `1` for a brick and `0` for a hole, stored as
`DATA`:

```basic norun
LABEL LAY1
DATA "1111111111"
DATA "1111111111"
DATA "1111111111"
DATA "1111111111"
DATA "1111111111"
DATA "1111111111"

LABEL LAY2
DATA "0011111100"
DATA "0111111110"
DATA "1111111111"
DATA "1111111111"
DATA "0111111110"
DATA "0011111100"

LABEL LAY3
DATA "1010101010"
DATA "0101010101"
DATA "1111001111"
DATA "1100110011"
DATA "1011111101"
DATA "0110110110"
```

`READ` takes the next `DATA` item, and `RESTORE` moves that cursor to a given place.
`RESTORE` accepts a label, so each layout is simply a named position in the `DATA` stream
and choosing one is three `IF`s:

```basic norun
LABEL LOADLAY
N# = MOD((LEVEL# - 1), 3)
IF N# = 0 THEN RESTORE LAY1
IF N# = 1 THEN RESTORE LAY2
IF N# = 2 THEN RESTORE LAY3
FOR R# = 0 TO 5
  READ LAY$(R#)
NEXT R#
RETURN
```

Adding a fourth level is a `DATA` block and one more `IF`.

**One `READ` cursor walks every `DATA` item in the file, in the order they were written**,
no matter which routine is doing the reading. If you have two things to load — a font and
a table, say — the one whose `DATA` comes first in the file must be loaded first, or use
`RESTORE` to say where to start.

### The grid

Turn those strings into a flat array of sixty numbers, and count how many bricks there
are while you are at it:

```basic norun
LABEL BUILDW
LEFTN# = 0
FOR R# = 0 TO 5
  S$ = LAY$(R#)
  GOSUB BUILDR
NEXT R#
RETURN

LABEL BUILDR
FOR C# = 0 TO 9
  T$ = MID(S$, C#, 1)
  I# = (R# * BCOLS#) + C#
  BR#(I#) = 0
  IF T$ = "1" THEN BR#(I#) = 1
  IF T$ = "1" THEN LEFTN# = LEFTN# + 1
  SX# = (BLEFT# + (C# * BRW#)) * CW#
  SY# = (BTOP# + R#) * CH#
  IF T$ = "1" THEN SOLID I# + 1, SX#, SY#, SX# + (BRW# * CW#), SY# + CH#
  IF T$ = "0" THEN SOLID I# + 1
NEXT C#
RETURN
```

Two things happen per cell, and the second is what Step 10 is built on. `BR#()` is the
program's own record of which bricks are left. **`SOLID` tells the interpreter**, so it can
answer "did the ball hit a brick, and which one" instead of the program working it out.

The id is the array index plus one — `SOLID` numbers from 1 and the array from 0 — so a
rectangle and its array element are the same brick with no lookup between them. A hole
retires whatever was there, which matters because a level change reuses the ids.

The rectangle is in pixels, and this is the only place the cell grid and the pixel grid meet:
a brick at column `C#` starts at `(BLEFT# + C# * BRW#) * CW#` and is `BRW# * CW#` wide.

`MID` counts from **zero** here, unlike Commodore BASIC. `BR#(row * 10 + col)` is the
brick at that cell; `LEFTN#` is how many are left, so "is the level finished" is a
comparison rather than a scan of sixty cells.

### Drawing a row

`CHAR` writes a string into the text grid at a row and column. It has one property that
decides how the rest of this section is written: **`CHAR` terminates the row where it
stops.** Writing at column 12 erases everything from column 13 to the end of the line.

So do not write bricks one at a time. Build the whole row as a string and write it once,
from column 0:

```basic
DIM LAY$(6)
DIM BSG$(6)
BSG$(0) = "[##]"
BSG$(1) = "[##]"
BSG$(2) = "[==]"
BSG$(3) = "[==]"
BSG$(4) = "[--]"
BSG$(5) = "[--]"
LAY$(0) = "1111111111"
LAY$(1) = "1111111111"
LAY$(2) = "1101111011"
LAY$(3) = "1111111111"
LAY$(4) = "1011110111"
LAY$(5) = "0110110111"
S$ = ""
T$ = ""
R# = 0
C# = 0
FOR R# = 0 TO 5
  GOSUB BUILDROW
  PRINT S$
NEXT R#
END

LABEL BUILDROW
S$ = "     "
FOR C# = 0 TO 9
  T$ = MID(LAY$(R#), C#, 1)
  IF T$ = "1" THEN S$ = S$ + BSG$(R#)
  IF T$ = "0" THEN S$ = S$ + "    "
NEXT C#
RETURN
```

```output
     [##][##][##][##][##][##][##][##][##][##]
     [##][##][##][##][##][##][##][##][##][##]
     [==][==]    [==][==][==][==]    [==][==]
     [==][==][==][==][==][==][==][==][==][==]
     [--]    [--][--][--][--]    [--][--][--]
         [--][--]    [--][--]    [--][--][--]
```

A missing brick contributes four spaces, so every row is the same length and the columns
line up. That block uses `PRINT`, so it runs on either build — which makes it a good way
to check your layouts before you have a window.

In the game, replace the `PRINT S$` with a `CHAR`, and use the real left margin:

```basic norun
LABEL DRAWBR
S$ = ""
IF BLEFT# > 0 THEN S$ = " " * BLEFT#
BSEG$ = BSG$(BR2#)
FOR CC# = 0 TO 9
  I# = (BR2# * BCOLS#) + CC#
  IF BR#(I#) = 1 THEN S$ = S$ + BSEG$
  IF BR#(I#) = 0 THEN S$ = S$ + "    "
NEXT CC#
R2# = BTOP# + BR2#
CHAR 1, 0, R2#, S$
RETURN
```

`" " * BLEFT#` repeats a string, which is how you get a margin of any width.

**Tell the rows apart by shape, not by colour.** `CHAR` accepts a colour argument and
ignores it — the text layer draws in one colour — so `[##]`, `[==]` and `[--]` are what
makes a 60-point row look different from a 10-point one.

Drawing the whole wall is then six calls:

```basic norun
LABEL DRAWW
FOR R# = 0 TO 5
  BR2# = R#
  GOSUB DRAWBR
NEXT R#
RETURN
```

## Step 6: Write the main loop

**Goal: a loop that runs one frame's worth of work and comes back, for as long as the game
lasts.**

Write the main loop with `LABEL` and `GOTO`:

```basic norun
LABEL TICK
GOSUB READKEY
IF STATE# <> 0 THEN GOTO DISPATCH
IF PAUSED# = 1 THEN GOTO TICKEND
GOSUB MOVEPAD
IF HELD# = 1 THEN GOSUB HOLDBAL
IF HELD# = 0 THEN GOSUB MOVEBAL
GOSUB SHOWSPR
LABEL TICKEND
SLEEP 0.02
GOTO TICK

LABEL DISPATCH
IF STATE# = 1 THEN GOTO LOSTLIF
IF STATE# = 2 THEN GOTO LEVELUP
IF STATE# = 3 THEN GOTO BYE
IF STATE# = 5 THEN GOTO NEWGAME
STATE# = 0
GOTO TICK
```

**A label is one bare word: letters and digits, no underscore.** `TICKEND` is a label;
`TICK_END` is a parse error, and the message you get is `UNKNOWN TOKEN _` rather than
anything about naming, so it is worth not writing in the first place. The same goes for
variable names.

`STATE#` is a plain number that the rest of the game writes when something has happened:
0 is playing, 1 is "the ball was lost", 2 is "the level is clear", 3 is "quit", 5 is
"start a new game". Nothing acts on it where it is set — the loop notices on the next pass
and branches. That keeps every state change in one place and out of the middle of the
physics.

The branch targets end in `GOTO TICK` rather than `RETURN`. Nothing `GOSUB`s into a state
change, so the subroutine stack is empty again by the time the next frame begins.

**`SLEEP 0.02` is the frame pacing, and it does not block the host.** It records a
deadline and the interpreter declines to advance your program until the clock reaches it,
so the window keeps redrawing and the keyboard keeps being read the whole time. 0.02
seconds asks for fifty frames a second.

### Why `GOTO` rather than `DO ... LOOP`

A `DO ... LOOP` around the frame would read better, and it is not usable here: **a `GOTO`
that jumps out of a `FOR` or a `DO` does not release the loop's scope.** There are 12
scopes, so a game that leaves its main loop once per lost life stops on the
twelfth one:

```basic
N# = 0
LABEL TOP
DO
  N# = N# + 1
  IF N# < 100 THEN GOTO TOP
LOOP UNTIL N# > 99
PRINT "SURVIVED " + N#
```

```output
? 3 : PARSE ERROR Environment pool exhausted at line 3 (12 in use)

```

A `LABEL`/`GOTO` loop pushes no scope at all, so it can run for as long as the machine is
on. Use `FOR` and `DO` freely for work that finishes inside a frame — the wall builder in
Step 5 is a `FOR` inside a `FOR` — and use `GOTO` for anything you will branch out of.
This is [`TODO.md` §6 item 37](../TODO.md); when it is fixed, `DO ... LOOP` will be
available for a main loop too, and a `GOTO` loop will still be correct.

## Step 7: Read the keyboard

**Goal: a paddle that moves smoothly while a key is held, using the only input verb there
is.**

`GET` takes one keystroke from a queue the host fills, and returns 0 if there is nothing
waiting. It never blocks. There is **no key-up event and no way to ask whether a key is
currently down**.

What you get instead is the operating system's own key repeat, arriving as ordinary
keypresses about once a frame while a key is held. So: drain the queue every frame, and
let each keystroke refill a countdown.

```basic norun
LABEL READKEY
FOR KI# = 1 TO 8
  GET K#
  IF K# <> 0 THEN GOSUB HANDKEY
NEXT KI#
RETURN

LABEL HANDKEY
IF K# = 1073741904 THEN PDIR# = 0 - 1
IF K# = 1073741904 THEN PDEC# = 12
IF K# = 1073741903 THEN PDIR# = 1
IF K# = 1073741903 THEN PDEC# = 12
IF K# = 32 THEN GOSUB KEYSPC
IF K# = 112 THEN GOSUB KEYPAU
IF K# = 113 THEN STATE# = 3
IF K# = 27 THEN STATE# = 3
RETURN
```

Eight `GET`s a frame is enough to keep the queue from backing up. `PDIR#` is which way to
move and `PDEC#` is how many more frames to keep moving; a keypress sets both.

The key codes are the host's. 1073741903 and 1073741904 are the right and left arrows, 32
is space, 112 is `P`, 113 is `Q` and 27 is escape. [Chapter 12](12-function-reference.md)
says where they come from. A quick way to find any other key is to print what you get:

```basic norun
LABEL SHOWKEY
GET K#
IF K# <> 0 THEN PRINT "KEY " + K#
GOTO SHOWKEY
```

Note `0 - 1` rather than `-1` in `PDIR# = 0 - 1`. Both work; writing the subtraction out
is the habit that goes with the parenthesising rule from Step 3, and it is what the rest
of this chapter does.

## Step 8: Move the paddle

**Goal: the paddle moves while the countdown lasts, and stops at both edges.**

```basic norun
LABEL MOVEPAD
IF PDEC# < 1 THEN GOTO PADCLMP
PDEC# = PDEC# - 1
PX# = PX# + (PDIR# * PSPD#)
LABEL PADCLMP
IF PX# < 0 THEN PX# = 0
M# = SCW# - PW#
IF PX# > M# THEN PX# = M#
RETURN
```

The countdown is the whole trick. A single tap sets `PDEC#` to 12 and the paddle coasts
for twelve frames; holding the key down refills it faster than it drains, so the paddle
keeps going. **Held reads as held and tapped reads as a nudge, with no held-key state
anywhere.**

The clamp is written as a jump to `PADCLMP` rather than wrapped around the movement,
because the paddle has to be pushed back inside the window whether it moved this frame or
not.

`M# = SCW# - PW#` is computed into a variable rather than written inline. Any expression
you are about to compare or pass is clearer that way, and it keeps lines short — **a line
here holds at most 32 tokens**, so long conditions want breaking up into named pieces
anyway.

Going over 32 currently stops the interpreter rather than raising a BASIC error you could
`TRAP`, which makes a too-long line harder to diagnose than it should be. That is recorded
in [`TODO.md` §8](../TODO.md), and the fix is to report it as the parse error it is; the
limit itself stays either way, so short lines are the habit regardless.

## Step 9: Move the ball

**Goal: a ball that moves, bounces off three walls, and is lost off the bottom.**

The ball has a position (`BX#`, `BY#`) and a velocity (`BVX#`, `BVY#`) in pixels per
frame. Moving it is adding one to the other — but do the two axes **separately**, and test
each move on its own:

```basic norun
LABEL MOVEBAL
BX# = BX# + BVX#
IF BX# < 0 THEN GOSUB WALLL
IF BX# > MAXX# THEN GOSUB WALLR
BY# = BY# + BVY#
IF BY# < TOPY# THEN GOSUB WALLT
GOSUB PADHIT
IF BY# > LOSEY# THEN STATE# = 1
RETURN
```

**Nothing here tests a brick.** Step 10 arms a handler that fires when the ball meets one,
and it pushes the ball out along the contact rather than restoring a remembered position —
so there is no "where was it before" to keep.

A wall bounce puts the ball on the wall and flips the sign of that axis:

```basic norun
LABEL WALLL
BX# = 0
BVX# = 0 - BVX#
RETURN

LABEL WALLR
BX# = MAXX#
BVX# = 0 - BVX#
RETURN

LABEL WALLT
BY# = TOPY#
BVY# = 0 - BVY#
RETURN
```

There is no wall at the bottom. Below `LOSEY#` the ball is gone, and the loop's dispatch
in Step 6 picks that up.

Draw a visible ceiling once, at startup, so the ball turns against something the player
can see:

```basic norun
FRAME$ = "=" * COLS#
CHAR 1, 0, 1, FRAME$
```

## Step 10: Break bricks

**Goal: find out which brick the ball hit, and take it out of the wall.**

Step 5 registered every brick with `SOLID`, so this is not arithmetic — it is a question.
Arm a handler:

```basic norun
COLLISION 2, BRICKHIT
```

That line goes in the setup block, once, before the frame loop starts — arming a handler is
a standing instruction, not something a frame does.

`COLLISION 2` fires when a sprite overlaps one of those rectangles. The handler runs
**between source lines**, exactly like a `GOSUB` the program did not write, and must end in
`RETURN`.

```basic norun
LABEL BRICKHIT
M# = BUMP(2)
IF (M# AND 1) = 0 THEN RETURN
T# = RCOLLISION(1, 1)
IF T# < 1 THEN RETURN
IF BR#(T# - 1) = 0 THEN RETURN
D% = RCOLLISION(1, 4)
BX# = BX# + (RCOLLISION(1, 2) * D%)
BY# = BY# + (RCOLLISION(1, 3) * D%)
A# = RCOLLISION(1, 7)
IF A# = 1 THEN BVX# = 0 - BVX#
IF A# = 2 THEN BVY# = 0 - BVY#
BI# = T# - 1
BR2# = BI# / BCOLS#
GOSUB KILLBR
RETURN
```

Read it as four questions and an answer.

**`BUMP(2)` is the mask of which sprites met static geometry**, and bit 0 is sprite 1 — the
ball. Reading it clears it, so the next hit is news again. `BUMP(1)` is a *separate*
accumulator for sprite-against-sprite, so this handler never sees the paddle.

**`RCOLLISION(1, 1)` is which rectangle.** Because Step 5 registered brick `I#` as id
`I# + 1`, that number is the array index plus one and nothing has to be looked up. The two
guards after it are worth keeping: a program can be told about a brick it has already
broken, because the handler runs a line or two after the overlap happened.

**Fields 2, 3 and 4 push the ball out.** Field 4 is how deep the overlap is and fields 2 and
3 are the direction out of the brick, so adding one times the other puts the ball exactly
clear. That is why `MOVEBAL` in Step 9 keeps no `OX#`/`OY#` backup — there is nothing to
restore to.

`D%` is a float variable, and it has to be: field 4 is a float and a `#` would throw the
fraction away. The products land in `BX#` and `BY#`, which *are* integers — and that is
safe here for a reason worth knowing rather than assuming. A box against a box gives a
normal that is exactly -1, 0 or 1, so the product is a whole number before it is stored.
Against a circle it would not be, and the push-out would land a pixel short.

**Field 7 is which axis to reverse.** It is the one the ball is least far through, which is
what makes a ball clipping the end of a row go sideways rather than straight back down.
Working it out yourself means comparing two floats, which is exactly where
[Chapter 13](13-differences.md)'s left-operand rule catches people, so it is computed for
you.

Breaking the brick clears its cell, scores it, and redraws **just that row**:

```basic norun
LABEL KILLBR
BR#(BI#) = 0
SOLID BI# + 1
LEFTN# = LEFTN# - 1
PTS# = (BROWS# - BR2#) * 10
SCORE# = SCORE# + PTS#
GOSUB DRAWBR
GOSUB DRAWHUD
IF LEFTN# < 1 THEN STATE# = 2
RETURN
```

**`SOLID BI# + 1` retires the rectangle in the same breath as clearing the array.** Miss it
and the ball goes on bouncing off a brick that is no longer drawn, which is a bewildering
thing to debug and an easy thing to forget.

The top row is worth 60 and the bottom row 10. `LEFTN#` reaching zero sets the state that
Step 6's dispatch turns into a level change.

## Step 11: Bounce off the paddle

**Goal: a bounce whose angle is decided by where on the paddle the ball landed.**

This is the part that makes it a game rather than a demonstration. Divide the paddle into
five zones and let the zone choose the horizontal speed:

```basic norun
LABEL PADHIT
IF BVY# < 1 THEN RETURN
BB# = BY# + 8
IF BB# < PY# THEN RETURN
IF BY# > (PY# + 10) THEN RETURN
RX# = PX# + PW#
IF (BX# + 8) < PX# THEN RETURN
IF BX# > RX# THEN RETURN
BY# = PY# - 8
BVY# = 0 - BSPD#
Z# = ((BX# + 4) - PX#) / (PW# / 5)
IF Z# < 0 THEN Z# = 0
IF Z# > 4 THEN Z# = 4
PVX# = BVX#
BVX# = (Z# - 2) * 3
IF BVX# <> 0 THEN GOTO PADAIM
BVX# = 2
IF PVX# < 0 THEN BVX# = 0 - 2
LABEL PADAIM
RETURN
```

The first five lines are the overlap test, each written so it can bail out. `Z#` comes out
0 to 4, so `(Z# - 2) * 3` gives horizontal speeds of -6, -3, 0, +3 and +6. Catch the ball
on the left of the paddle and it goes left; catch it in the middle and it goes straight
up.

**Straight up is a problem, so the middle zone does not give it.** A ball with no sideways
speed rises and falls down the same column for ever and never reaches a brick it has not
already broken. The last three lines before `PADAIM` catch that case and give the ball a
shallow angle in the direction it arrived from instead.

That handles the obvious case. The subtle one is a ball that has found some other orbit
missing the wall, and the cure for that is a watchdog. Count frames since the last brick,
and after ten seconds' worth mark the ball for a new angle. **Add these two lines to the
end of `MOVEBAL`** from Step 9, just before its `RETURN`:

```basic norun
STALL# = STALL# + 1
IF STALL# > 500 THEN NUDGE# = 1
```

and **add one line to `KILLBR`** from Step 10, so that hitting a brick resets the count:

```basic norun
STALL# = 0
```

Then apply the nudge at the **next paddle bounce**, never in mid-air — a ball that changes
direction in open space looks exactly like it hit something invisible. **Add this line to
`PADHIT` above**, immediately before `LABEL PADAIM`:

```basic norun
IF NUDGE# = 1 THEN GOSUB UNSTICK
```

```basic norun
LABEL UNSTICK
NUDGE# = 0
STALL# = 0
BVX# = (RND(4) * 3) - 6
IF BVX# = 0 THEN BVX# = 3
RETURN
```

### Random numbers are built in

There is no `INT`, `SQR` or `TIMER` in this dialect, but
`RND(n)` returns an integer from zero through `n - 1`. It seeds itself
from the host clock the first time it is called, so a program only needs the bound:

```basic
I# = 0
FOR I# = 1 TO 5
  PRINT "ROLL " + (RND(6) + 1)
NEXT I#
END
```

Use `RND` for the serve, too, so the ball does not always leave in the same direction:

```basic norun
LABEL SERVE
PX# = (SCW# - PW#) / 2
HELD# = 1
BX# = PX# + ((PW# / 2) - 4)
BY# = PY# - 10
BVX# = BSPD#
IF RND(2) = 0 THEN BVX# = 0 - BSPD#
BVY# = 0 - BSPD#
PDEC# = 0
GOSUB SHOWSPR
RETURN
```

<details>
<summary>Historical aside: the LCG this chapter used to teach</summary>

Before `RND` existed, this nine-token linear congruential generator was copied into
every program. It remains a useful from-scratch PRNG example:

```basic norun
SEED# = 12345
RMAX# = 6
ROLL# = 0
I# = 0
FOR I# = 1 TO 5
  GOSUB RANDOM
  PRINT "ROLL " + (ROLL# + 1)
NEXT I#
END

LABEL RANDOM
SEED# = MOD(((SEED# * 1103515245) + 12345), 2147483648)
ROLL# = MOD((SEED# / 65536), RMAX#)
RETURN
```

The multiplication stays inside a 64-bit integer for any seed below 2147483648. The
answer is taken from the middle bits because the low bits of a power-of-two modulus
barely change from one call to the next. This used to be required; it is now built in.

</details>

`HELD#` is the flag Step 6's loop tests: while it is 1 the ball sits on the paddle, and
`HOLDBAL` keeps it there:

```basic norun
LABEL HOLDBAL
BX# = PX# + ((PW# / 2) - 4)
BY# = PY# - 10
RETURN
```

Space clears `HELD#` and the ball launches. That is the `KEYSPC` that Step 7's `HANDKEY`
calls:

```basic norun
LABEL KEYSPC
IF HELD# = 0 THEN RETURN
HELD# = 0
GOSUB CLRMSG
RETURN
```

Step 15 adds two lines to the top of it.

## Step 12: Draw the HUD and the messages

**Goal: a status line and centred messages, both drawn the way `CHAR` wants.**

Same rule as the brick rows: build the whole line as one string, then write it once.

```basic
V# = 0
P$ = ""
H$ = ""
SCORE# = 1250
LIVES# = 3
LEVEL# = 2
HIGH# = 9900
V# = SCORE#
GOSUB PAD6
H$ = "  SCORE " + P$
H$ = (H$ + "   LIVES ") + LIVES#
H$ = (H$ + "   LEVEL ") + LEVEL#
V# = HIGH#
GOSUB PAD6
H$ = (H$ + "   HIGH ") + P$
PRINT H$
END

LABEL PAD6
P$ = "" + V#
DO WHILE LEN(P$) < 6
  P$ = "0" + P$
LOOP
RETURN
```

```output
  SCORE 001250   LIVES 3   LEVEL 2   HIGH 009900
```

In the game that becomes a routine called `DRAWHUD`, whose last line is
`CHAR 1, 0, 0, H$` instead of `PRINT H$`; everything else is the same, which means you can
develop the HUD on either build. [Step 16](#step-16-put-the-program-together) has it
written out.

`"" + V#` turns a number into a string, and `PAD6` pads it to six digits so the line does
not change width as the score grows. Every `+` after the first is parenthesised, for the
reason in Step 3.

A centred message needs no padding on the right, because `CHAR` terminating the row is
what erases whatever was there before:

```basic norun
LABEL SHOWAT
L# = LEN(MSG$)
C2# = (COLS# - L#) / 2
S$ = MSG$
IF C2# > 0 THEN S$ = (" " * C2#) + MSG$
CHAR 1, 0, MROW#, S$
RETURN

LABEL CLRAT
CHAR 1, 0, MROW#, " "
RETURN
```

Set `MSG$` and `MROW#`, then `GOSUB SHOWAT`. Clearing a message is a single space written
at column 0 — one character, and the terminator behind it takes the rest of the row with
it.

Two small wrappers save repeating the row number:

```basic norun
LABEL SHOWMSG
MROW# = MSGROW#
GOSUB SHOWAT
RETURN

LABEL CLRMSG
MROW# = MSGROW#
GOSUB CLRAT
RETURN
```

## Step 13: Lives, levels and game over

**Goal: the states from Step 6, written out.**

Each of these is a branch target, not a subroutine. It does its work and jumps back to
`TICK`.

Losing a ball:

```basic norun
LABEL LOSTLIF
LIVES# = LIVES# - 1
GOSUB DRAWHUD
IF LIVES# < 1 THEN GOTO GAMEOVR
GOSUB SERVE
MSG$ = "BALL LOST -- PRESS SPACE"
GOSUB SHOWMSG
STATE# = 0
GOTO TICK
```

Clearing a level. The ball speeds up each time, to a ceiling:

```basic norun
LABEL LEVELUP
MSG$ = "LEVEL CLEARED"
GOSUB SHOWMSG
SLEEP 1.5
LEVEL# = LEVEL# + 1
IF BSPD# < 7 THEN BSPD# = BSPD# + 1
GOSUB NEWLEV
STATE# = 0
GOTO TICK

LABEL NEWLEV
GOSUB LOADLAY
GOSUB BUILDW
GOSUB DRAWW
GOSUB DRAWHUD
GOSUB SERVE
MSG$ = "PRESS SPACE TO LAUNCH"
GOSUB SHOWMSG
RETURN
```

Game over waits for a key in a small loop of its own:

```basic norun
LABEL GAMEOVR
MSG$ = "GAME OVER -- SPACE PLAYS AGAIN, Q QUITS"
GOSUB SHOWMSG
LABEL GOWAIT
GET K#
IF K# = 32 THEN GOTO NEWGAME
IF K# = 113 THEN GOTO BYE
IF K# = 27 THEN GOTO BYE
SLEEP 0.05
GOTO GOWAIT
```

And quitting turns the sprites off, so they are not left on the screen behind the final
message:

```basic norun
LABEL BYE
SPRITE 1, 0
SPRITE 2, 0
SPRITE 3, 0
SPRITE 4, 0
SCNCLR
PRINT "BREAKOUT"
PRINT "FINAL SCORE " + SCORE#
PRINT "HIGH SCORE  " + HIGH#
SLEEP 2
QUIT
```

`SCNCLR` clears the text screen and `QUIT` ends the interpreter; both are in
[Chapter 11](11-verb-reference.md). Turning the sprites off first matters because a sprite
is drawn over the text, and a final score behind four sprites is not a final score.

The high score is one comparison, called whenever the score changes:

```basic norun
LABEL HISCORE
IF SCORE# > HIGH# THEN HIGH# = SCORE#
RETURN
```

**There is nowhere to save it.** This interpreter has no disk — see
[Chapter 9](09-files-and-disk.md) — so the high score lasts as long as the process does.

## Step 14: Add sound

**Goal: sound where there is a sound device, silence where there is not, and no crash
either way.**

`SOUND` refuses on a machine with no audio device, and an untrapped refusal ends the
program. So ask once at startup, remember the answer, and never ask again. Here is the
idea on its own, as a program you can run to see which kind of machine you are on:

```basic requires=noakgl
SND# = 1
TRAP NOAUDIO
SOUND 1, 2000, 1
TRAP
IF SND# = 1 THEN PRINT "SOUND IS AVAILABLE"
IF SND# = 0 THEN PRINT "NO AUDIO DEVICE, PLAYING SILENTLY"
END

LABEL NOAUDIO
SND# = 0
RESUME NEXT
```

```output
NO AUDIO DEVICE, PLAYING SILENTLY
```

That output is from the plain build, which has no devices at all; on the SDL build the
same program prints the other line.

`TRAP NOAUDIO` arms a handler. `RESUME NEXT` returns to the statement after the one that
failed. **`TRAP` with no argument disarms it again** — leave it armed and the next
refusal anywhere in your game is silently swallowed. See
[Chapter 4](04-control-flow.md#trapping-errors).

In the game that becomes a routine and its handler, called once from the setup block
before anything else makes a noise:

```basic norun
LABEL SNDPROBE
SND# = 1
TRAP NOAUDIO
SOUND 1, 2000, 1
TRAP
RETURN

LABEL NOAUDIO
SND# = 0
RESUME NEXT
```

`NOAUDIO` has no `RETURN` of its own, and must not have one: `RESUME NEXT` is what leaves a
handler, and it goes back into `SNDPROBE` at the `TRAP` after the `SOUND` — so the disarm
still happens and the `RETURN` after it is the one that runs.

After that, every sound is one line guarded by the flag:

```basic norun
LABEL BEEPB
IF SND# = 1 THEN SOUND 1, 12000, 2
RETURN

LABEL BEEPP
IF SND# = 1 THEN SOUND 2, 6000, 3
RETURN

LABEL BEEPW
IF SND# = 1 THEN SOUND 3, 9000, 1
RETURN

LABEL BEEPL
IF SND# = 1 THEN SOUND 1, 1500, 20
RETURN
```

Then call them. Each is one `GOSUB` added to a routine you already have:

| Add | To | From |
|---|---|---|
| `GOSUB BEEPB` | `KILLBR`, before its `RETURN` | [Step 10](#step-10-break-bricks) |
| `GOSUB BEEPP` | `PADHIT`, at `LABEL PADAIM` | [Step 11](#step-11-bounce-off-the-paddle) |
| `GOSUB BEEPW` | `WALLL`, `WALLR` and `WALLT`, in all three | [Step 9](#step-9-move-the-ball) |
| `GOSUB BEEPL` | `LOSTLIF`, as its first line | [Step 13](#step-13-lives-levels-and-game-over) |

So `WALLL` from Step 9 becomes:

```basic norun
LABEL WALLL
BX# = 0
BVX# = 0 - BVX#
GOSUB BEEPW
RETURN
```

and `WALLR` and `WALLT` take the same line in the same place.

**`SOUND`'s frequency argument is a SID register value, not hertz.** The pitch you get is
`register * 1022730 / 16777216`, so 12000 is about 732 Hz. Work the notes you want out
once and write the numbers down in a comment beside them;
[Chapter 7](07-sound.md#sound) has the arithmetic.

## Step 15: Add an attract mode

**Goal: a title screen that plays the game by itself.**

This is not decoration. A demo that plays for two minutes exercises the ball, the bricks,
the level change and the speed-up *together*, for thousands of frames, which is the only
way some defects show up at all.

One flag is the whole difference between the demo and a real game:

```basic norun
LABEL TITLE
DEMO# = 1
SCORE# = 0
LIVES# = 3
LEVEL# = 1
BSPD# = 4
GOSUB LOADLAY
GOSUB BUILDW
GOSUB DRAWW
GOSUB DRAWHUD
GOSUB TITTEXT
GOSUB SERVE
STATE# = 0
GOTO TICK
```

Everything else is four small edits to routines you already have. Each one says which.

**In `MOVEPAD`** from Step 8, add these two lines at the top, immediately after the
`LABEL`, so that a demo paddle is driven by the machine instead of by `PDEC#`:

```basic norun
IF DEMO# = 1 THEN GOSUB DEMOPAD
IF DEMO# = 1 THEN GOTO PADCLMP
```

The demo paddle tracks the ball — but **aims off-centre by a random amount**, chosen
afresh at every bounce:

```basic norun
LABEL DEMOPAD
TX# = (BX# + 4) - (PW# / 2)
TX# = TX# + DOFF#
D# = TX# - PX#
IF D# > PSPD# THEN D# = PSPD#
M# = 0 - PSPD#
IF D# < M# THEN D# = M#
PX# = PX# + D#
RETURN

LABEL DEMOAIM
DOFF# = RND(81) - 40
RETURN
```

`DOFF#` is between -40 and +40 pixels of deliberate error, so the machine plays like
something with a hand on the paddle and occasionally misses. **A demo that tracks
perfectly never loses a ball and therefore never tests losing one.**

`DEMOAIM` has to be called from somewhere, and the somewhere is the bounce. **In `PADHIT`**
from Step 11, beside the `NUDGE#` line and immediately before `LABEL PADAIM`:

```basic norun
IF DEMO# = 1 THEN GOSUB DEMOAIM
```

**In `KEYSPC`** from Step 11, add two lines at the top, so that space starts a real game
rather than launching the demo's ball:

```basic norun
LABEL KEYSPC
IF DEMO# = 1 THEN STATE# = 5
IF DEMO# = 1 THEN RETURN
IF HELD# = 0 THEN RETURN
HELD# = 0
GOSUB CLRMSG
RETURN
```

**In `LOSTLIF`** from Step 13, add one line at the top, so a lost ball re-serves rather
than costing a life:

```basic norun
LABEL LOSTLIF
IF DEMO# = 1 THEN GOTO DEMOSRV
LIVES# = LIVES# - 1
```

with the branch target it needs:

```basic norun
LABEL DEMOSRV
GOSUB SERVE
HELD# = 0
STATE# = 0
GOTO TICK
```

**In `SERVE`** from Step 11, add one line after `HELD# = 1`, so the demo's ball launches by
itself:

```basic norun
IF DEMO# = 1 THEN HELD# = 0
```

**In `KILLBR`** from Step 10, guard the scoreboard, because the machine does not get on it:

```basic norun
IF DEMO# = 0 THEN GOSUB HISCORE
```

Leave it running and watch the score climb. That is your test suite for everything the
unit tests cannot reach.

## Step 16: Put the program together

**Goal: one file, in an order that runs.**

A program runs from the top, so the order of the file matters in three places and nowhere
else: the setup has to come first, `DATA` has to be in the order it will be read, and every
`LABEL` has to exist somewhere. Subroutines can go in any order you like.

This is the shape of the whole file:

```text
LABEL SETUP           the geometry from Step 2
                      the declaration block from Step 3
                      the brick faces from Step 5
                      RND(n) seeds itself from the host clock
                      the ceiling from Step 9
                      GOSUB MKSPR       Step 4
                      GOSUB SNDPROBE    Step 14
                      COLLISION 2, BRICKHIT   Step 10
                      GOTO TITLE

  the sprite routine, the sound routines, the title screen,
  the game and level setup, the main loop, the input routines,
  the paddle, the ball, the drawing routines, the state changes
  --- in any order ---

  the sprite patterns as DATA        Step 4
  the level layouts as DATA          Step 5
```

The two `DATA` blocks come last because nothing else in the program uses `DATA`, and the
sprite patterns are read before the layouts because `MKSPR` runs before `LOADLAY` does.
Change that order and each loader gets the other one's numbers.

### Declare all of it

Step 3 showed the shape of the declaration block. Here it is in full — every name the
finished game uses, and nothing gets to be created later:

```basic norun
DIM BR#(60)
DIM SB#(63)
DIM SP#(63)
DIM LAY$(6)
DIM BSG$(6)

SCORE# = 0
HIGH# = 0
LIVES# = 3
LEVEL# = 1
LEFTN# = 0
BSPD# = 4
STATE# = 0
DEMO# = 0
PAUSED# = 0
HELD# = 0
PDIR# = 0
PDEC# = 0
PX# = 0
BX# = 0
BY# = 0
BVX# = 0
BVY# = 0
K# = 0
HIT# = 0
PVX# = 0
DOFF# = 0
STALL# = 0
NUDGE# = 0
BI# = 0
BR2# = 0
PTS# = 0
SX# = 0
SY# = 0
A# = 0
M# = 0
D% = 0.0
V# = 0
L# = 0
C2# = 0
D# = 0
M# = 0
X2# = 0
X3# = 0
Z# = 0
BB# = 0
RX# = 0
N# = 0
MROW# = 0
SND# = 0
P$ = ""
H$ = ""
S$ = ""
T$ = ""
MSG$ = ""
BSEG$ = ""
FRAME$ = ""
I# = 0
R# = 0
R2# = 0
C# = 0
CC# = 0
KI# = 0
T# = 0
```

That is 65 names out of the 128 the interpreter has. Loop counters are in there too —
`I#`, `R#`, `C#`, `CC#`, `KI#` — because a `FOR` creates its counter the same way a
`GOSUB` creates a local, and declaring them costs nothing.

### The routines the earlier steps referred to but did not show

Four small ones, for completeness.

Loading the sprite patterns at startup, which is Step 4 turned into a routine:

```basic norun
LABEL MKSPR
FOR I# = 0 TO 62
  READ SB#(I#)
NEXT I#
FOR I# = 0 TO 62
  READ SP#(I#)
NEXT I#
SPRSAV SB#, 1
SPRITE 1, 1, 2
SPRSAV SP#, 2
SPRSAV SP#, 3
SPRSAV SP#, 4
SPRITE 2, 1, 15, 0, 1, 0
SPRITE 3, 1, 15, 0, 1, 0
SPRITE 4, 1, 15, 0, 1, 0
RETURN
```

Note this reads **all 63 numbers** for each pattern, so the `DATA` at the foot of the file
is 21 lines of three numbers per sprite rather than the shortened form Step 4's figure
used. Here are both, and the ball's is worth reading against the bit diagram in Step 4:

```basic norun
DATA 60, 0, 0
DATA 126, 0, 0
DATA 255, 0, 0
DATA 255, 0, 0
DATA 255, 0, 0
DATA 255, 0, 0
DATA 126, 0, 0
DATA 60, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0

DATA 255, 255, 255
DATA 255, 255, 255
DATA 255, 255, 255
DATA 255, 255, 255
DATA 255, 255, 255
DATA 255, 255, 255
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
DATA 0, 0, 0
```

Eight rows of ball in the top-left corner and thirteen empty ones; six solid rows of paddle
and fifteen empty ones. The zeros are not optional — `MKSPR` reads 63 numbers per pattern
and will take them from the level layouts if they are not there.

The HUD, which is Step 12's block with `CHAR` instead of `PRINT`:

```basic norun
LABEL DRAWHUD
V# = SCORE#
GOSUB PAD6
H$ = "  SCORE " + P$
H$ = (H$ + "   LIVES ") + LIVES#
H$ = (H$ + "   LEVEL ") + LEVEL#
V# = HIGH#
GOSUB PAD6
H$ = (H$ + "   HIGH ") + P$
CHAR 1, 0, 0, H$
RETURN
```

Pause, which is the `P` key from Step 7, and which the demo ignores:

```basic norun
LABEL KEYPAU
IF DEMO# = 1 THEN RETURN
PAUSED# = 1 - PAUSED#
IF PAUSED# = 1 THEN MSG$ = "PAUSED"
IF PAUSED# = 1 THEN GOSUB SHOWMSG
IF PAUSED# = 0 THEN GOSUB CLRMSG
RETURN
```

Starting a real game, which is what `STATE# = 5` dispatches to, and the title text and its
eraser:

```basic norun
LABEL NEWGAME
DEMO# = 0
SCORE# = 0
LIVES# = 3
LEVEL# = 1
BSPD# = 4
PAUSED# = 0
GOSUB CLRTIT
GOSUB NEWLEV
STATE# = 0
GOTO TICK

LABEL TITTEXT
MROW# = TITROW#
MSG$ = "B R E A K O U T"
GOSUB SHOWAT
MROW# = TITROW# + 2
MSG$ = "PRESS SPACE TO PLAY"
GOSUB SHOWAT
MROW# = TITROW# + 4
MSG$ = "ATTRACT MODE"
GOSUB SHOWAT
RETURN

LABEL CLRTIT
MROW# = TITROW#
GOSUB CLRAT
MROW# = TITROW# + 2
GOSUB CLRAT
MROW# = TITROW# + 4
GOSUB CLRAT
RETURN
```

### Check it before you have a window

Run the assembled file through the plain build first:

```sh norun
$ ./build/basic mybreakout.bas
```

It will stop at the first `RGR` with a message about a missing graphics device — which
means everything above that point parsed, and that is the whole of what this check is for.
A parse error, a bad line number or an `OUT OF DATA` here is a real problem, and it is far
easier to find without a window in the way. Then run it properly:

```sh norun
$ ./build-akgl/basic mybreakout.bas
```

## The rules this listing never breaks

A checklist to write your own game against.

| Rule | Because | Where |
|---|---|---|
| `DIM` at the top, never inside a loop or a `GOSUB` | An array created inside a scope takes pool storage that is never returned | [Step 3](#step-3-declare-every-name-first) |
| Declare any name a subroutine has to answer through | A name first seen inside a `GOSUB` dies at `RETURN`, silently | [Step 3](#step-3-declare-every-name-first) |
| Parenthesise every mixed `+` and `-` | `a - b + c` is currently evaluated as `a - (b + c)` | [Step 3](#step-3-declare-every-name-first) |
| Parenthesise a second `AND` or `OR` | Only one unparenthesised `AND` or `OR` is matched per expression | [Step 3](#step-3-declare-every-name-first) |
| Compute a `MOVSPR` coordinate into a variable first | A leading sign means *move by*, not *move to* | [Step 4](#step-4-make-the-ball-and-the-paddle) |
| Retire a `SOLID` when the thing it stood for is gone | The ball goes on bouncing off a brick that is no longer drawn | [Step 10](#step-10-break-bricks) |
| Build a text row whole and write it from column 0 | `CHAR` terminates the row where it stops | [Step 5](#step-5-build-the-brick-wall) |
| Tell rows apart by shape, not colour | `CHAR` ignores its colour argument | [Step 5](#step-5-build-the-brick-wall) |
| Loop the game with `GOTO`, and never jump out of a `DO` | A `GOTO` out of a loop does not release the loop's scope, and there are 32 | [Step 6](#step-6-write-the-main-loop) |
| Name things with letters and digits only | There is no underscore in an identifier, and the error names the character rather than the name | [Step 6](#step-6-write-the-main-loop) |
| Keep a line under 32 tokens | The 33rd stops the interpreter rather than raising an error you can `TRAP` | [Step 8](#step-8-move-the-paddle) |
| Span a loop across lines, and never write `FOR I# = 1 TO 1` | A whole loop on one line does not loop; equal bounds run the body zero times | [Chapter 13](13-differences.md) |
| Probe for a device once and remember the answer | An untrapped refusal ends the program | [Step 14](#step-14-add-sound) |

## The picture at the top of this chapter

Every figure in this guide is generated by running the listing beside it, and the one at
the top of this chapter is no exception. It is the game's own drawing code — the row
builder from Step 5, the sprite patterns from Step 4, the HUD from Step 12 — with the
numbers filled in by hand and no main loop, so it draws one frame and stops.

Type it in and you have a still of the game before you have written any of the game:

```basic requires=akgl screenshot=breakout-game size=800x600 text=1
DIM SB#(63)
DIM SP#(63)
DIM BSG$(6)
DIM LAY$(6)
I# = 0
R# = 0
C# = 0
S$ = ""
T$ = ""
SCNCLR
COLS# = RWINDOW(1)
BLEFT# = (COLS# - 40) / 2
BSG$(0) = "[##]"
BSG$(1) = "[##]"
BSG$(2) = "[==]"
BSG$(3) = "[==]"
BSG$(4) = "[--]"
BSG$(5) = "[--]"
LAY$(0) = "1111111111"
LAY$(1) = "1111111111"
LAY$(2) = "1111111111"
LAY$(3) = "0111111110"
LAY$(4) = "0110110110"
LAY$(5) = "0010110100"
CHAR 1, 0, 0, "  SCORE 001250   LIVES 3   LEVEL 2   HIGH 009900"
CHAR 1, 0, 1, "=" * COLS#
FOR R# = 0 TO 5
  S$ = " " * BLEFT#
  FOR C# = 0 TO 9
    T$ = MID(LAY$(R#), C#, 1)
    IF T$ = "1" THEN S$ = S$ + BSG$(R#)
    IF T$ = "0" THEN S$ = S$ + "    "
  NEXT C#
  I# = 4 + R#
  CHAR 1, 0, I#, S$
NEXT R#
CHAR 1, 0, 35, "          PRESS SPACE TO LAUNCH"
FOR I# = 0 TO 62
  SB#(I#) = 0
  SP#(I#) = 0
NEXT I#
FOR I# = 0 TO 7
  READ SB#(I# * 3)
NEXT I#
FOR I# = 0 TO 17
  SP#(I#) = 255
NEXT I#
SPRSAV SB#, 1
SPRSAV SP#, 2
SPRSAV SP#, 3
SPRSAV SP#, 4
SPRITE 1, 1, 2
SPRITE 2, 1, 15, 0, 1, 0
SPRITE 3, 1, 15, 0, 1, 0
SPRITE 4, 1, 15, 0, 1, 0
MOVSPR 1, 396, 518
MOVSPR 2, 328, 528
MOVSPR 3, 376, 528
MOVSPR 4, 424, 528

DATA 60, 126, 255, 255, 255, 255, 126, 60
```

![](images/breakout-game.png)

## Where to go next

- **[Chapter 18](18-tutorial-breakout-artwork.md)** builds Breakout again out of loaded
  artwork, with powerups and a coloured HUD. It is a bigger program and it teaches the
  drawing verbs, which this chapter never uses.
- **[Chapter 13](13-differences.md)** is the full list of what this dialect does
  differently from BASIC 7.0.
- **[Chapter 8](08-sprites.md)** is the sprite reference, and
  **[Chapter 4](04-control-flow.md)** is the whole of `GOSUB`, `TRAP` and the loop forms.
- **[Chapter 14](14-architecture.md)** is the interpreter itself: the step loop, the pools
  and how to debug a program that stops for no visible reason.
