ZalaXa 4 — First Glimpse of Multicolour

Well here we are! If you pull the latest commits from GitHub. you should see the code for part 4 of the tutorial.

If you Assemble And Run \tutorials\part4\src\main.asm in Zeus, you’ll see the familiar menu we wrote in part 3. This time, if you press space, hopefully you’ll see some multicolour animation!

Let’s try and have a look at what I added. First of all, you will notice there are now eight source files, in which I’ve reorganised the previous code, and added some new code:

Many assemblers allow this, and it does help to organise your code. In Zeus, it’s done with the include directive:

25
26
27
28
29
30
31
32
33
; main.asm
 
include                 "menu.asm"
include                 "sprites.asm"
include                 "utilities.asm"
include                 "database.asm"
include                 "constants.asm"
include                 "macros.asm"
include                 "nirvana+.asm"

The last file (which is last deliberately, and I’ll explain why later) is Einar’s source code for NIRVANA+, taken directly from his Dropbox drive. We won’t look at this in detail for now—suffice it to say it has an NIRVANA+ API, and we can call routines to do magic multicolour things.

The /tiles/nirvana+.btile file also comes from Einar’s Dropbox. This file contains 16×16 pixel multicolour tiles, in a special 8×2 attribute format tailored for NIRVANA.

ZX-Paintbrush is a graphical editing tool we will find indispensible for working with btiles. Download it from Klaus Jahn’s website here (by clicking on the image).

If you open the file in ZX-Paintbrush, you can see it contains the 17 sprites from part 1 (by Dave “R-Tape” Hughes):

A slightly closer examination reveals the important detail—each 8×2 pixel block can have exactly one background and foreground colour (and its own brightness and flash value), enabling the multicolour magic!

All I’m doing here is cycling between the first two btiles in this set, to do some simple but effective animation. First we clear the standard 8×8 attributes (for a fast clean CLS), then we set the index and coordinates of NIRVANA+ sprite A (there are eight of them) to the first btile in the top left hand corner, then we enable NIRVANA+:

17
18
19
20
21
22
23
24
25
26
27
; menu.asm
 
SetupGame               proc
                        call ClsAttr                    ; Clear the 8x2 attributes for a fast CLS before setup
                        ld a, BTile.NirvanaDemo         ; BTile.NirvanaDemo is 0 - the index of the first tile in the set
                        ld (Sprites.AIndex), a          ; Set NIRVANA+ sprite A to this sprite index
                        ld hl, $1000                    ; LSB is $00 (the column), MSB is $10 (the line, decimal 16)
                        ld (Sprites.AColumn), hl        ; Set NIRVANA+ sprite A coords to 0, 16
                        call NIRVANA_start              ; Enable NIRVANA+
                        ret
pend

NIRVANA+ horizontal coordinates range from 0 to 31—standard Spectrum character columns. Vertical coordinates range from 0 to 215. NIRVANA+ never draws anything multicolour on the first character row. It also allows you to draw a tile completely off the top or bottom of the screen, so the visible range is actually between 16 and 199. Don’t worry too much about this for now, just take note that pixel line 16 is the top of the visible NIRVANA+ screen.

Our main loop now has a call to AnimateDemo, 50 times a second:

17
18
19
20
21
22
23
; main.asm
 
Loop:
                        halt                            ; Wait until the next 50th second frame
                        call AnimateDemo                ; Animate our monster
                        jp Loop                         ; Go into an endless loop (for now...)
pend

The AnimateDemo routine reads the lowest byte of the Spectrum ROM’s frame counter, which is increment every 50th of a second by NIRVANA’s interrupt handler—when it goes above 255 it wraps back round to zero. It turns that into a number between 0 and 7 with a fancy bitwise modulus calculation using the and opcode. There are 32 lots of 8 in the 256 possible values of a byte, so this is a clever fast way of counting in eights (well, between 0 and 7).

So, for 7 out of every 8 frames, it returns without doing anything.

3
4
5
6
7
8
9
10
11
12
13
14
15
; sprites.asm
 
AnimateDemo             proc
 
                        ld a, (FRAMES)                  ; Read the LSB of the ROM frame counter (0.255)
                        and %00000111                   ; Take the lowest 3 bits (effectively FRAMES modulus 8),
                        ret nz                          ;   and return 7 out of every 8 frames.
 
                        ld a, (Sprites.AIndex)          ; For every 8th frame, read Sprite A's tile index,
                        xor %00000001                   ;   alternate between (0 => 1 => 0 => 1=> etc),
                        ld (Sprites.AIndex), a          ;   then save it back.
                        ret
pend

But for one frame in every eight, it flips the btile index of sprite A between 0 and 1 using a bitwise xor operation. In other words we do a two-frame animation, alternating every 0.16 of a second!

We won’t keep any of this code in the final game, but it neatly demonstrates two things:

  • we don’t need to do anything too fancy to set up NIRVANA+, and
  • a little animation really helps bring graphics to life.

More next time!

Leave a Reply

Your email address will not be published. Required fields are marked *