If you take a screenshot of the part 7 code and look at it in a screen editor such as ZX-Paintbrush, you’ll see we’re setting attributes to black-on-black1 but not clearing pixels. This is going to cause us problems later when we start writing to the screen, so let’s address that now.
We’ll still clear the 8×8 attributes, because that happens very fast and gives a nice snappy transition. But let’s add a
ClsNirvana routine that we call afterwards:
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
; utilities.asm ClsNirvana proc di ; 1) Clear all pixels ld (RestoreStack), sp ; SMC> Save the stack ld sp, AttributeAddress ; Set stack to end of screen ld de, $0000 ; All pixels unset ld b, 0 ; Loop 256 times: 12 words * 256 = 6144 bytes LoopPixels: loop 12 push de lend djnz LoopPixels RestoreStack equ $+1: ld sp, SMC ; <SMC Restore the stack ld hl, ClsNirvanaGame ; 2) Clear 8x2 attributes ld ix, race_raster ld de, NAttrVOffset xor a ld (Col+1), a LoopAttr: ld b, (hl) xor a cp b jp z, TopRow inc hl ld c, (hl) inc hl Times: ld a, (Col+1) cp 32 jp nz, Skip xor a add ix, de Skip: inc a ld (Col+1), a Col: ld a, (deltas-1) ; NIRVANA_org+8957 (65280, $FF00) ld (Delta+2), a Delta: ld (ix+0), c djnz Times jp LoopAttr TopRow: ClsAttrLine(0, BrightRedBlackP) ; 3) Clear top row of 8x8 attributes ret pend
This is split into three sections[I believe Einar Saukas, the author of NIRVANA+, gave me the original version of this routine, although I’ve hacked it about several times since. Thanks, Einar![/note]:
- Pixel clear: This uses a faster, stack-based way of block copying bytes than we used in the
ldir-based ClsAttr routine (part 3).
- Multicolour attribute clear: This is the fiddly one. there are 2944 ($B80) multicolour attributes, and they aren’t laid out contiguously in memory. In fact the attributes for column 7 aren’t even near the attributes for column 8, for example. Every line of attributes is laid out 82 bytes after the previous line, moving down the screen. To find anything else, we need to use the
deltaslookup table that NIRVANA+ handily provides. The upshot is that we need a slightly more complicated routine to set these attributes. This section uses a colour table for more flexibility. I’ll talk about this in more detail in a minute.
- Top row attribute clear: In NIRVANA+, the top row of attributes are always rendered with standard 8×8 attributes. The third section does this. Here, I’m setting them to red, because the arcade Galaga displays red status text on the top row. You can configure NIRVANA+ to render some of the lower rows with 8×8 attributes too. The main advantage of doing this is to to reclaim some of the processor time used for drawing the attributes for your user code, if your program design can get away with not having multicolour over the full screen. For this reason, I’m being slightly flexible and writing this section with a macro, which allows me to specify the row I want to clear2:
21 22 23 24 25 26 27 28 29 30 31 32 33 34
; macros.asm ClsAttrLine macro(Line, Colour) if Colour = DimBlackBlackP xor a else ld a, Colour endif ld hl, AttributeAddress+(Line*32) ld (hl), a ld de, AttributeAddress+(Line*32)+1 ld bc, 32 ldir mend
I usually set any pixels and 8×8 attributes at the end of setup routines, as they can sometimes display earlier than the multicolour parts, particularly if you have NIRVANA+ turned off while you do the setup. I don’t think it matters much here, but it’s helpful to keep this as the last section of
The colour table used by the second section looks like this. It consists of pairs of bytes, with a zero byte terminator. The first byte of each pair is a count, and the second byte is a colour. The counts should add up to 2944. By all means make them add up to less, but if they add up to more, code will get overwritten and weird things will happen. Be warned!
Here, I’m setting the second character row to white on black (32 columns x 4 attribute lines = 128), as we’ll display scores here. The rest of the screen will get cleared to yellow on black. Our bullets will probably be yellow, and this might make the drawing code slightly easier if the screen is already the right colour.
35 36 37 38 39 40 41 42 43 44
; database.asm ClsNirvanaGame proc db 128, BrightWhiteBlackP loop 11 db 255, BrightYellowBlackP lend db 11, BrightYellowBlackP db 0 pend
The sprites (only the ship, so far) have their own background and foreground colours, and will always overlay attribute values written this way, so we don’t need to worry about them here.
I defined a whole bunch of colour constants uing
equ. This lets us refer to named foreground and background colours when we hardcode them. Check them out on line 81 of constants.asm, if you’re interested.
If you want to see at least some visible change, play around with the
ClsNirvanaGame colour table. It can be as long or complicated as you like! See if you can make a blocky pattern out of individual attributes. I used this technique to animate clouds on the Jet Power Jack main menu—notice how both the blue and white clouds go behind most of the graphics, but go in front of a few parts – the letters p, e and k in the title, for example:
Yes, this really is the 406th version of Jet Power Jack, and counting3. One day it will get finished and released…
That’s all for today! Let’s get fancy with proportional fonts next time 🙂
- Actually, we’re setting 8×8 attributes to black-on-black, but not the 8×2 multicolour attributes. The latter just happen to be black anyway when the program is first loaded, but they probably won’t be always be—for example, if we write code later to restart the game.
xor ais a slightly faster way of writing
ld a, 0.
- Specifically, my 406th git commit.