Files
akbasic/examples/breakout/characters
Andrew Kesterson cb0e2d0800
Some checks failed
akbasic CI Build / cmake_build (push) Failing after 3m10s
akbasic CI Build / sanitizers (push) Failing after 4m5s
akbasic CI Build / coverage (push) Failing after 3m29s
akbasic CI Build / akgl_build (push) Failing after 21s
akbasic CI Build / mutation_test (push) Failing after 3m19s
Add two Breakout examples and the tutorials that build them
Two complete games in `examples/breakout/`, both 100% BASIC: `characters/`
draws its wall in the text grid with two `DATA` sprites for the ball and
paddle, and `sprites/` loads CC0 artwork and captures its whole screen with
`SSHAPE`/`SPRSAV`. They take opposite shapes for reasons that are entirely
this interpreter's, which is what the chapters are for.

`docs/17-tutorial-breakout.md` and `docs/18-tutorial-breakout-artwork.md`
build each one a step at a time, and end in a checklist of the rules a real
program runs into: create every name before the loop starts, write a text row
whole, loop with `GOTO` rather than `DO`, put the float on the left. Every
trap is a runnable block with its own output rather than a claim -- the value
pool dying at four thousand names, the skipped `BEGIN` block that breaks its
caller's `RETURN`, `SSHAPE` ignoring a subscript, `READ`'s single cursor.

Five figures, generated from the listings beside them by `docs_screenshots`,
and a `breakout_art` setup so the ones that load artwork load the example's
own. The character game's wall cannot be photographed -- the screenshot host
omits the text layer on purpose -- so it is shown as compared output instead.

`docs/07-sound.md` never said `SOUND`'s frequency is a SID register value
rather than hertz, which both games depend on. It says so now, with the
conversion from `src/audio_tables.c:84`.

`TODO.md` gains the thirteen defects the two games turned up -- §6 items 30
to 33 and all of §9 -- each with a reduction that fits on a screen, the file
and line of the cause, and what a fix would touch.

Verified: `docs_examples` passes in both build configurations,
`docs_screenshots --check` re-renders all thirteen figures and byte-compares
them, the full 109-test suite passes in both builds, every quoted fragment
was checked to appear verbatim in the listing it came from, and every
relative link and anchor resolves.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 22:54:42 -04:00
..

Breakout

Breakout, written entirely in BASIC for the AKGL BASIC interpreter. The ball and the paddle are sprites defined from DATA in the listing; the bricks, the HUD and the messages are characters in the text grid.

../../../build-akgl/basic breakout.bas

It needs the SDL build. The stdio build has no graphics device, so RGR refuses on the fourth line and the game stops there — which is exactly what it should do.

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

The title screen plays itself. Attract mode is a real feature and it is also how the game was tested without a hand on the keyboard.

Three lives, six rows of bricks worth 60 down to 10 points a row, three level layouts that repeat with a faster ball each time, and a high score that lasts as long as the process does.

How it works, and how to write your own

Chapter 17 of the guide builds this program a step at a time: what to make a sprite and what to make a character, why every name is declared before the game starts, how a text row has to be written whole, and the rest of the rules this listing never breaks. It is the tutorial; this is the finished thing.

Chapter 18 does the same for ../sprites, which builds the same game out of loaded artwork and comes out a completely different program.

Known warts, this game's own

  • The cell size is a constant. CW# and CH# are 16, measured with the bundled C64_Pro_Mono at 16 points in the 800×600 window; the grid is 50×37. BASIC cannot ask — WINDOW knows, but the standalone frontend never offers it. Change the font or the window size and those two numbers have to change with them.
  • Every character the game draws also goes to stdout, because the frontend tees the text sink to the terminal. It made the whole game auditable from a log file during development and it is pure noise the rest of the time. Redirect it.
  • Collision is against the cell the ball's leading edge is in, so a brick clipped at the very corner can be missed by up to seven pixels' worth of ball. Testing the centre instead was worse: the ball sank four pixels into a brick before it turned.
  • There is a stall watchdog. Ten seconds without touching a brick and the ball gets a new angle — at the next paddle bounce, never in mid-air.
  • The demo cannot lose, it re-serves. It also cannot be paused; P is ignored until a real game starts.
  • Sound is asked for once and then believed. On a machine with no audio device the game is silent rather than dead.
  • No high score on disk. There is no disk in this interpreter.

The interpreter defects this game turned up are filed in TODO.md §6 item 30 and §9, each with a reduction that fits on a screen.

How this was checked

  • Parses clean under the stdio basic (it then stops at the first graphics verb, as it should).
  • Attract mode run for 145 seconds and again for 110: no runtime error, score climbing throughout, 39 bricks in the second run.
  • Level clear verified against a copy whose first layout is a single row: LEVEL CLEARED, layout 2 loaded, ball speed up, play continues.
  • Input driven with xdotool against the real window: paddle moves and clamps at both edges, ball launches, P pauses and unpauses, three lives drain to GAME OVER, space starts a new game, Q exits printing the final and high scores.
  • Every direction change logged for a whole run and read back: each one is a wall, a brick or the paddle. Nothing turns without a reason.