Give chapter 18 the six pieces a reader had to invent
A reader building the game from the chapter alone had to guess at all of these, and three of them are code the chapter describes and never shows: - the HUD eraser stamp, promised in Step 6 as "make a second one while you are here" and then never given - the gem roll at the end of ONEBRICK, without which nothing ever drops - BX1# and BY1#, which SPAWNGEM reads and only ONEBRICK can set And three rules the chapter leans on without stating: - MID and INSTR count from zero, which is what makes a glyph number an array index with no adjustment - sprite n sets bit 2^(n-1), which is where 16, 32 and 64 come from - states 5 and 6 have no tick routine on purpose; that is what a pause is Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EwxGB6TdoVvZ11KQQME9cL
This commit is contained in:
@@ -411,7 +411,18 @@ RETURN
|
|||||||
|
|
||||||
Make a second one the width of the HUD strip while you are here, for the same reason: the
|
Make a second one the width of the HUD strip while you are here, for the same reason: the
|
||||||
strip is rewritten whenever a number in it changes, and the old digits have to go
|
strip is rewritten whenever a number in it changes, and the old digits have to go
|
||||||
somewhere before the new ones are drawn.
|
somewhere before the new ones are drawn. It is the same code with a bigger rectangle:
|
||||||
|
|
||||||
|
```basic norun
|
||||||
|
FOR K# = 0 TO 59
|
||||||
|
DRAW 1, 0, 160 + K# TO 799, 160 + K#
|
||||||
|
NEXT K#
|
||||||
|
SSHAPE Z$, 0, 160, 800, 220 : HBL$ = Z$
|
||||||
|
```
|
||||||
|
|
||||||
|
Both blocks belong at the end of `DRAWPROTOS` in Step 4, drawn below the six brick
|
||||||
|
prototypes and captured with them, so the eight `SSHAPE` slots are all spent in one place.
|
||||||
|
`HBL$` is stamped at the top of the HUD redraw and `BL$` by `ERASEBRICK`.
|
||||||
|
|
||||||
**This is what makes the whole field a draw-once job.** Draw the walls and all sixty bricks
|
**This is what makes the whole field a draw-once job.** Draw the walls and all sixty bricks
|
||||||
when a level is laid out, and after that touch only what changes. A program that had to
|
when a level is laid out, and after that touch only what changes. A program that had to
|
||||||
@@ -504,7 +515,11 @@ DATA 4, 0,6, 0,30, 3,33, 6,36
|
|||||||
4-unit `SCORE` in the HUD.
|
4-unit `SCORE` in the HUD.
|
||||||
|
|
||||||
Turning a character into a glyph number is one call: `INSTR(ALPHA$, MID(TX$, TXI#, 1))`
|
Turning a character into a glyph number is one call: `INSTR(ALPHA$, MID(TX$, TXI#, 1))`
|
||||||
over an alphabet string. That is why the order of the `DATA` lines matters — they have to
|
over an alphabet string. **`MID` and `INSTR` both count from zero in this dialect**, which
|
||||||
|
is the opposite of Commodore BASIC and the opposite of most other BASICs — `MID(A$, 0, 1)`
|
||||||
|
is the first character, and `INSTR` answers 0 for a match at the front and −1 for no match
|
||||||
|
at all. That is what makes the glyph number an array index with no adjustment, and it is
|
||||||
|
also why `MID("0123456789", D#, 1)` turns a digit straight into its character. That is why the order of the `DATA` lines matters — they have to
|
||||||
match the order of the characters in `ALPHA$`. The finished game uses a 41-character
|
match the order of the characters in `ALPHA$`. The finished game uses a 41-character
|
||||||
alphabet covering `A` to `Z`, `0` to `9`, space, colon, dash, full stop and exclamation
|
alphabet covering `A` to `Z`, `0` to `9`, space, colon, dash, full stop and exclamation
|
||||||
mark.
|
mark.
|
||||||
@@ -700,7 +715,8 @@ RETURN
|
|||||||
```
|
```
|
||||||
|
|
||||||
**The mask is by sprite, and the balls are sprites 5, 6 and 7** — so their bits are 16, 32
|
**The mask is by sprite, and the balls are sprites 5, 6 and 7** — so their bits are 16, 32
|
||||||
and 64, not 1, 2 and 4. That is the same `5 + B#` arithmetic `MOVSPR` uses for them
|
and 64, not 1, 2 and 4. Sprite *n* sets bit 2 to the power of *n* − 1: sprite 1 is 1,
|
||||||
|
sprite 2 is 2, sprite 3 is 4, sprite 4 is 8, sprite 5 is 16, and so on to sprite 8 at 128. That is the same `5 + B#` arithmetic `MOVSPR` uses for them
|
||||||
everywhere else, and getting it wrong costs nothing visible: the handler runs, tests bits
|
everywhere else, and getting it wrong costs nothing visible: the handler runs, tests bits
|
||||||
nothing sets, and returns.
|
nothing sets, and returns.
|
||||||
|
|
||||||
@@ -724,11 +740,23 @@ SOLID N# + 1
|
|||||||
BRN# = BRN# - 1
|
BRN# = BRN# - 1
|
||||||
SCORE# = SCORE# + BRV#(R#)
|
SCORE# = SCORE# + BRV#(R#)
|
||||||
SOUND 1, 17175 - R# * 2100, 4
|
SOUND 1, 17175 - R# * 2100, 4
|
||||||
|
BX1# = BRKX# + C# * 72
|
||||||
|
BY1# = BRKY# + R# * 24
|
||||||
GOSUB ERASEBRICK
|
GOSUB ERASEBRICK
|
||||||
GOSUB HUDTEXT
|
GOSUB HUDTEXT
|
||||||
|
IF GMON# = 1 THEN RETURN
|
||||||
|
RNMAX# = 7
|
||||||
|
GOSUB NEXTRAND
|
||||||
|
IF RNVAL# = 0 THEN GOSUB SPAWNGEM
|
||||||
RETURN
|
RETURN
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`BX1#` and `BY1#` are the broken brick's top-left corner in pixels, and they are set here
|
||||||
|
because this is the only routine that knows it — Step 9's `SPAWNGEM` starts the gem falling
|
||||||
|
from that spot. The last four lines are the whole of "a broken brick drops a gem about one
|
||||||
|
time in seven": one roll, and `IF GMON# = 1 THEN RETURN` first because there is one gem
|
||||||
|
sprite and a gem already falling means no roll at all.
|
||||||
|
|
||||||
Fields 2, 3 and 4 push the ball exactly clear along the contact normal. Field 7 is which
|
Fields 2, 3 and 4 push the ball exactly clear along the contact normal. Field 7 is which
|
||||||
axis to reverse — **the minimum translation axis**, which is why a ball clipping the end of
|
axis to reverse — **the minimum translation axis**, which is why a ball clipping the end of
|
||||||
a row goes sideways rather than straight back down. Working that out by hand means building
|
a row goes sideways rather than straight back down. Working that out by hand means building
|
||||||
@@ -976,6 +1004,12 @@ Each is a subroutine called once a frame while that state is current. This is a
|
|||||||
shape from Chapter 17's branch targets, and it works here because nothing jumps out of a
|
shape from Chapter 17's branch targets, and it works here because nothing jumps out of a
|
||||||
loop to reach it.
|
loop to reach it.
|
||||||
|
|
||||||
|
There are seven state numbers and only five tick routines. **5 is game over and 6 is
|
||||||
|
paused, and neither has one on purpose**: the frame loop's `IF STATE# = n THEN GOSUB` list
|
||||||
|
simply has no line for them, so the frame draws whatever is on the screen, reads the
|
||||||
|
keyboard and does nothing else. That is exactly what a pause is, and writing an empty
|
||||||
|
subroutine to say so would cost a label.
|
||||||
|
|
||||||
```basic norun
|
```basic norun
|
||||||
LABEL TITLETICK
|
LABEL TITLETICK
|
||||||
STIMER# = STIMER# + 1
|
STIMER# = STIMER# + 1
|
||||||
|
|||||||
Reference in New Issue
Block a user