Files
akbasic/docs/17-tutorial-breakout.md
Tachikoma 2688183ef0 Say where the collision handler is armed, and what BYE's last two verbs do
A reader building chapter 17 from the text alone had to infer that
COLLISION 2, BRICKHIT belongs in the setup block rather than the frame
loop, and met SCNCLR and QUIT for the first time in the assembly step.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EwxGB6TdoVvZ11KQQME9cL
Co-Authored-By: Andrew Kesterson <andrew@aklabs.net>
2026-08-02 13:20:34 -04:00

50 KiB

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

The finished listing is 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:

$ ./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 — get a program onto the screen, and find out which build you need
  • Step 2 — measure the screen and work the geometry out from what you measured
  • Step 3 — declare every name the program will use, before anything uses it
  • Step 4 — make the ball and the paddle out of sprite data
  • Step 5 — build the brick wall out of characters, and keep a grid saying which bricks are still there
  • Step 6 — write the main loop and the frame pacing
  • Step 7 — read the keyboard without blocking
  • Step 8 — move the paddle and keep it on the screen
  • Step 9 — move the ball and bounce it off the walls
  • Step 10 — find out which brick the ball hit, and break it
  • Step 11 — bounce off the paddle at an angle the player chooses
  • Step 12 — draw the HUD and the messages
  • Step 13 — handle lives, levels and game over
  • Step 14 — add sound, on a machine that may not have any
  • Step 15 — add a title screen that plays itself
  • Step 16 — 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:

PRINT "HELLO"
END
HELLO

Save that as first.bas and run it:

$ ./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:

PRINT "BEFORE"
SPRITE 1, 1, 2
PRINT "AFTER"
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$.

N# = 40
PRINT "SCORE " + N#
END
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:

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:

BRW# = 4