Rear Gunner XL – Part 3 – Drawing

Having converted the first five lines of the game in the last post, which setup the positions of the player and enemy, we can move onto the next four lines, which are concerned with drawing both the player’s sights and enemy:

; 50 PRINT AT D,C;”(graphic G)”
; 60 PRINT AT A,B;” + “
; 70 PRINT AT A-1,B;”   “
; 80 PRINT AT A+1,B;”   “

Line 50 is drawing the enemy sights, and 60-80 the player.  It’s interesting to note that the player is drawn in the middle of a 3×3 square, surrounded by spaces, so when the player moves it erases the previous position as it goes.

The ZX81 has a character-mapped display, which means that rather than storing all the pixels required to fill the screen, it stores the actual characters instead.  This makes the drawing of characters on the screen very simple, as we just need to work out where in the display memory to put each one.

The address of the display memory is stored in the system variable named D_FILE, and from there we have to skip the first byte, then 33 bytes for each row (32 characters + newline) then add the column. So…

; Find the location of a character in the display memory
; Row in D, column in E
; HL returns with character address
FUNC_GETDFILE_ADDRESS
; Calculate 33 times the row.
 ld h, 0
 ld l, d
 add hl, hl ; x2
 add hl, hl ; x4
 add hl, hl ; x8
 add hl, hl ; x16
 add hl, hl ; x32
 ld b, 0
 ld c, d
 add hl, bc ; x33
; Add the column
 ld c, e
 add hl, bc
; Add to the base of the display memory (+1)
 ld de, (D_FILE)
 inc de
 add hl, de
; Return
 ret

So we now have a function we can pass a row & column position to, and get back the location in the display memory we need to write the characters to.  So for line 50:

; 50 PRINT AT D,C;”(graphic G)”

we need to read our C & D variables, get the address, then write a single character to it.  The character – graphic G – you’ll need to look-up in the manual, and is character 137:

ld a, (VARIABLE_D)
ld d, a
ld a, (VARIABLE_C)
ld e, a
call FUNC_GETDFILE_ADDRESS
ld (hl), 137

Lines 60 to 80 are just the same, but we write three characters each time, in successive columns:

; 60 PRINT AT A,B;” + “
 ld a, (VARIABLE_A)
 ld d, a
 ld a, (VARIABLE_B)
 ld e, a
 call FUNC_GETDFILE_ADDRESS
 ld (hl), __
 inc hl
 ld (hl), _ADD
 inc hl
 ld (hl), __

; 70 PRINT AT A-1,B;”   “
 ld a, (VARIABLE_A)
 dec a
 ld d, a
 ld a, (VARIABLE_B)
 ld e, a
 call FUNC_GETDFILE_ADDRESS
 ld (hl), __
 inc hl
 ld (hl), __
 inc hl
 ld (hl), __

; 80 PRINT AT A+1,B;”   “
 ld a, (VARIABLE_A)
 inc a
 ld d, a
 ld a, (VARIABLE_B)
 ld e, a
 call FUNC_GETDFILE_ADDRESS
 ld (hl), __
 inc hl
 ld (hl), __
 inc hl
 ld (hl), __

We can actually be much more efficient with that section, as we could draw the lines in row order – instead of centre, then above, then below – which would mean we could just add 33 to our display address to get to the next line.  We could also store the nine character in memory somewhere, and copy them from there to the display.  But for the sake of this first-pass, the above will be good enough I think.

This now makes our listing as follows:

; 5 PAUSE 50 
LINE_5:
 ld hl, 50
 call FUNC_WAITFORFRAMES

; 10 LET A=5 
 ld a, 5
 ld (VARIABLE_A), a

; 20 LET B=7 
 ld a, 7
 ld (VARIABLE_B), a
 
; 30 LET C=INT (RND*26) 
 ld b, 26
 call FUNC_GETRANDOM_RANGE
 ld (VARIABLE_C), a 

; 40 LET D=INT (RND*17) 
 ld b, 17
 call FUNC_GETRANDOM_RANGE
 ld (VARIABLE_D), a 

; 50 PRINT AT D,C;”(graphic G)” 
LINE_50:
 ld a, (VARIABLE_D)
 ld d, a
 ld a, (VARIABLE_C)
 ld e, a
 call FUNC_GETDFILE_ADDRESS
 ld (hl), 137 

; 60 PRINT AT A,B;” + “ 
 ld a, (VARIABLE_A)
 ld d, a
 ld a, (VARIABLE_B)
 ld e, a
 call FUNC_GETDFILE_ADDRESS
 ld (hl), __
 inc hl
 ld (hl), _ADD
 inc hl
 ld (hl), __ 

; 70 PRINT AT A-1,B;”   “ 
 ld a, (VARIABLE_A)
 dec a
 ld d, a
 ld a, (VARIABLE_B)
 ld e, a
 call FUNC_GETDFILE_ADDRESS
 ld (hl), __
 inc hl
 ld (hl), __
 inc hl
 ld (hl), __ 

; 80 PRINT AT A+1,B;”   “ 
 ld a, (VARIABLE_A)
 inc a
 ld d, a
 ld a, (VARIABLE_B)
 ld e, a
 call FUNC_GETDFILE_ADDRESS
 ld (hl), __
 inc hl
 ld (hl), __
 inc hl
 ld (hl), __ 

; 90 IF INKEY$=“5” THEN LET B=B-1 
; 100 IF INKEY$=“8” THEN LET B=B+1 
; 110 IF INKEY$=“7” THEN LET A=A-1 
; 120 IF INKEY$=“6” THEN LET A=A+1 
; 130 IF INKEY$=“0” THEN GOTO 150 
; 140 GOTO 50
; 150 IF D<>A THEN GOTO 50 
; 160 IF C=B THEN GOTO 170
; 170 PRINT AT D-1,C;”(graphic Y;SPACE;graphic T)”
; 180 PRINT AT D,C;”(SPACE;inverse SPACE;SPACE)”
; 190 PRINT AT D+1,C;”(graphic T;SPACE;graphic Y)”
; 200 RUN 


; Wait for HL frames 
FUNC_WAITFORFRAMES
; Load the system variable FRAMES with the number to wait for
; Remember to keep bit 15 high though
 set 7, h
 ld (FRAMES), hl 
FUNC_WAITFORFRAMES_LOOP
; Read the current value 
 ld hl, (FRAMES)
; Keep looping until it's zero (ignoring bit 15)
 ld a, h
 and %01111111 
 or l
 jp nz, FUNC_WAITFORFRAMES_LOOP
; Return
 ret 


; Get a random 8-bit number 
FUNC_GETRANDOM
; Calculate a new 'random' number from the last one and r-register 
 ld a, r
 ld hl, LMATH_GR_SEED
 add a, (hl)
 rrca
 ld (hl), a
 ret 
LMATH_GR_SEED
 defb 91 


; Get a random 8-bit number within a range 
; Call with B as the maximum value + 1 
FUNC_GETRANDOM_RANGE
 call FUNC_GETRANDOM 
FUNC_GETRANDOM_RANGE_LOOP:
 cp b
 ret c
 sub b
 jp FUNC_GETRANDOM_RANGE_LOOP 


VARIABLE_A
 defb 0 
VARIABLE_B 
 defb 0 
VARIABLE_C
 defb 0 
VARIABLE_D
 defb 0

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s