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
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.
/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).
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
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!