It captured the HUD strip into sprite 1 and the whole play field into sprite 2, and its own header called them "the screen". That was never a choice: a drawing lasted one frame, so a sprite was the only thing the interpreter would redraw for nothing. Both slots are free now, and five things went with them. **`WINDOW 0, 35, 49, 36` is the first executable line.** The text layer repaints every row it owns and by default owns the whole window; moved to two rows at the bottom, it leaves the other thirty-five to the drawing verbs, and what the program draws stays. **`PACE` is gone.** It spun on `TI#` until a batch boundary so an `SSHAPE` capture would not be cut in half by a present. Nothing is captured, so a drawing spanning two batches simply arrives over two frames and the layer keeps both halves. The 256-line drawing deadline that shaped every draw routine in this listing does not apply to it any more. **The flattened live list is gone** -- `BUILDLIVE`, `BUILDROW`, `STAMPROW` and the four arrays behind them. They existed so a full-field redraw could be one stamp and an advance per brick, and a full-field redraw existed because removing one brick meant rebuilding all sixty. A broken brick is now erased in place with a blank stamp, so the field is drawn once per level and not again. **`BALLBRICKS` and `TESTCELL` are gone** -- about sixty lines that turned the ball's box into a range of candidate cells, walked them with a nested `DO`, and computed an overlap rectangle to pick an axis. `SOLID` registers each brick as the level is laid out, `COLLISION 2` fires, and `RCOLLISION` says which brick, which way out, how far, and which axis to reverse. **The `SSHAPE` pool accounting is gone.** `SHN#` counted slots because every frame's capture spent another and `GRAPHIC 5` had to throw them all away periodically; eight are now spent once and never again. Three mistakes worth recording, because each was silent: - **The bricks were registered and then immediately thrown away.** `GOSUB BUILDLIVE` sat *after* the fill loop in `SETUPLEVEL` and meant "rebuild the list of what is standing"; replaced in place by a bare `SOLID`, it meant "retire everything" and ran after all sixty had been registered. Nothing failed -- the ball simply passed through the wall. - **The handler tested the wrong bits.** `BUMP` is a mask by *sprite*, and the balls are sprites 5, 6 and 7, so their bits are 16, 32 and 64. Testing 1, 2 and 4 asked about the HUD and field sprites that no longer exist. - **The eraser stamps were undeclared**, so `SSHAPE` filled them inside `DRAWPROTOS` and they were empty everywhere else -- exactly the scope trap chapter 17 Step 3 is about, found by printing the handle inside the routine and again outside it. Verified by driving it: a copy with a tracking paddle and auto-relaunch breaks thirteen bricks in sixty seconds with no error line, and the shipped listing runs clean. Both suites green. Chapter 18 still describes the architecture this commit removed; that is the rest of section 6 item 39. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwxGB6TdoVvZ11KQQME9cL
100 lines
5.1 KiB
Markdown
100 lines
5.1 KiB
Markdown
# Breakout, with artwork
|
|
|
|
Breakout, written entirely in BASIC for the AKGL BASIC interpreter, using downloaded CC0
|
|
sprite artwork for the paddles, the balls and the powerup gems. The bricks, the HUD and
|
|
the lettering are drawn — `WINDOW` moves the text layer to two rows at the bottom, and
|
|
everything the program draws then stays on the screen without being redrawn or captured.
|
|
|
|
The bricks are also **collidable without being sprites**: `SOLID` registers a rectangle
|
|
the interpreter collides against, so sixty of them cost none of the eight slots.
|
|
|
|
```sh
|
|
../../../build-akgl/basic breakout.bas
|
|
```
|
|
|
|
It needs the SDL build. Without a graphics device the first `SPRSAV` refuses by name and
|
|
the program stops there, which is the right thing for it to do.
|
|
|
|
| Key | Does |
|
|
|---|---|
|
|
| left / right | move the paddle |
|
|
| space | start a game, launch the ball, release a stuck ball |
|
|
| P | pause |
|
|
| S | sound on and off |
|
|
| Q or escape | quit |
|
|
|
|
Three lives, six rows of bricks worth 60 down to 10 points a row, and a field that cycles
|
|
six rows, then five, then four while the ball gets faster every level up to a ceiling. A
|
|
gem is worth 50 on top of whatever it does.
|
|
|
|
## The powerups
|
|
|
|
A broken brick drops a gem about one time in seven, and only ever one at a time. Catch it
|
|
with the paddle. The colour of the gem is what tells you which it is; the banner that
|
|
flashes over the field names it as well.
|
|
|
|
| Gem | Name | Does | For |
|
|
|---|---|---|---|
|
|
| red | EXPAND | doubles the paddle's width | 20 seconds |
|
|
| yellow | MULTI | throws two more balls off the one in play | until they are lost |
|
|
| green | SLOW | drops the ball's speed to about two thirds | 16 seconds |
|
|
| blue | STICKY | the ball sticks where it lands; space fires it | 18 seconds |
|
|
| purple | CATCH | a second bar appears higher up the field | 24 seconds |
|
|
|
|
The second bar **mirrors** the paddle rather than following it, so it covers the side you
|
|
just left. A second bar directly above the first is worth nothing; a mirrored one turns a
|
|
dive across the field into a save at both ends.
|
|
|
|
## How it works, and how to write your own
|
|
|
|
**[Chapter 18 of the guide](../../../docs/18-tutorial-breakout-artwork.md)** builds this
|
|
program in twelve steps: loading artwork, budgeting the eight sprite slots, capturing a
|
|
drawing into one, stamping the brick field, finding the host's frame boundary with `TI#`,
|
|
moving everything that is not drawing out of the deadline, the stroke font, the bounce
|
|
without a square root, and the gems.
|
|
|
|
[Chapter 17](../../../docs/17-tutorial-breakout.md) does the same for
|
|
[`../characters`](../characters), which builds the same game out of the text grid and two
|
|
`DATA` sprites — a completely different program, and the shorter one to read first.
|
|
|
|
## Where the artwork came from
|
|
|
|
Kenney's [Puzzle Pack 1](https://kenney.nl/assets/puzzle-pack-1), released under
|
|
[CC0](http://creativecommons.org/publicdomain/zero/1.0/). The files in `art/` are the
|
|
pack's own `PNG/Default/` versions, unmodified, with the pack's licence file beside them.
|
|
`art/PROVENANCE.md` says which file is used for what and why the double-size set is not.
|
|
|
|
Crediting Kenney is not required by CC0. It is here because it should be.
|
|
|
|
## What is not in it
|
|
|
|
Named honestly rather than left to be discovered:
|
|
|
|
- **No music under the game**, only event sounds and two four-note stings. There is room in
|
|
the third voice for it; there was not much room anywhere else when it was written. 121 of
|
|
the interpreter's 128 variables are spoken for and the label table is at 61 of 64 —
|
|
several of them spent working around defects that have since been fixed.
|
|
- **One gem at a time.** There is one sprite slot for it. A brick broken while a gem is
|
|
falling drops nothing.
|
|
- **Sticky and multiball share one offset.** Two balls stuck to the paddle at once sit on
|
|
top of each other. It is rare enough that fixing it would cost a variable I do not have.
|
|
- **The score lags a frame behind the bricks.** Only one capture happens per frame and the
|
|
field goes first, so a brick disappears one frame before the score that counts it. At
|
|
thirty frames a second nobody can see it, and it is a deliberate trade rather than an
|
|
oversight.
|
|
- **No high score on disk.** There is no disk.
|
|
|
|
The eight interpreter defects this game turned up are filed in `TODO.md` §9, each with a
|
|
reduction that fits on a screen and the file and line of the cause. **Six are now fixed**
|
|
— the leaking `DEF` call, the skipped block that broke its caller's `RETURN`, the ignored
|
|
subscript on `SSHAPE`, `GRAPHIC CLR`, a negative `DATA` item, and half of the invisible
|
|
drawing. The two that stand are the left-operand arithmetic rule, which turned out to be a
|
|
decision rather than a defect and is now documented as one, and the 256-line batch tear,
|
|
which belongs to the host.
|
|
|
|
**The listing's code is unchanged**, and deliberately: it is what a program written
|
|
against those constraints looks like, and none of the workarounds costs anything now that
|
|
they are not needed. Six separate scalars for six brick stamps, and loops guarded by
|
|
`GOTO` rather than wrapped in a block, are both still what the file does. Its comments say
|
|
which of the five traps stand and which are marked FIXED.
|