News:

Printed Amstrad Addict magazine announced, check it out here!

Main Menu
avatar_Kitsune Mifune

Advice on first tile routine (half working)

Started by Kitsune Mifune, 16:52, 12 June 20

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Kitsune Mifune

I've been inspired to have a stab as Z80 again so here goes.

It took a bit of courage to post this as I'm a little embarrassed about my bloated code, but I could do with some advice as it's not quite working right. I thought I'd have a go at writing my own tile paste routine from scratch, more so because I tend to get lost reading what other people have done, but I thought it was better than just copy/paste/hope for the best.

There's only two tiles in the bank for now, and the map makes a sort of checker board pattern on the screen using them (I figure I can add more tiles later).

The routine reads the tile map value (either &0 or &1 at the moment since there is only two tiles) then matches it with a tile bank index number which is supposed to then put the tile graphics data into 'de' then send it to be drawn. After that the coordinates for the position are recalculated to shift right (by the tile's width), and if the row is complete then shift down by 16 lines and and back to the left of the screen.

It's ham-fisted but it does work, although not very well (it's just pasting the same tile then the screen clears and starts drawing again), and I don't really know what to do now. I think the problem comes from when the actual graphics data is fetched from the bank, and I'll admit I had no clue what to do there, so it was literally just a pure guess on how to set that bit up.

Any advice, code tweaks/suggestions etc. would be most welcome.

Thank you!


- Screen is 256 x 192
- Mode 0
- Tiles are 16x16 (8x16 Mode 0)
- Draw routine isn't mine, it's thieved from the ChibiAkumas tutorials (I understand it though)

- I use a lot of labelled variables for easy reading ATM
- Done in WinAPE






;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; TILE MAPS AND BACKGROUND DRAWING ;;
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; GET WHICH TILE TO PASTE ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


DRAWTILES:
; TILE MAP SCAN (Find number of the tile in which to paste on the screen)


ld b,&10 ; 'b' is counter. &10 (176) - total no. of entries in tile map for on screen
ld hl,TILE_MAP ; Load TILE MAP data to 'hl'


TILE_PASTE_LOOP:

ld a,(hl) ; Load tile number from map
ld c,a ; store value in 'c' for comparison later with TILE BANK index
inc hl ; Increase for next loop


push hl


ld de,TILE_BANK
ld hl,(TILE_INDEX)


TILE_BANK_SCAN: ; TILE BANK SCAN (Find the tile associated with that number)


cp l
jr z, FOUND_TILE ; If a match is found then skip scan
inc hl
inc de
jr TILE_BANK_SCAN


FOUND_TILE:


ld (TILEPASTE),de ; Load tile data to variable for drawing...
; ...(I know this isn't needed but it's easier to read)
pop hl

;;;;;;;;;;;;;;;;;
;; POSITIONING ;;
;;;;;;;;;;;;;;;;;


push bc ; Save counter (b) and map data (hl)
push hl


ld a,(TILEPASTE_HCOUNT) ; Don't shift right on first tile
or a
jr z, SKIP_TILESHIFT_AT_START


ld a,&04 ; Paste tiles 4 bytes apart (16 pixels)
ld l,a
ld bc,(TILE_XY) ; Load into XY variable
ld a,b
add l ; Add 16 (4 BYTES) to X value in odrer to paste the next...
ld b,a ; ...tile 4 bytes to the right of the last one
ld (TILE_XY),bc ; Load result back into variable

SKIP_TILESHIFT_AT_START:


call TILE_DRAW_ROUTINE ; Draw tile


ld a,(TILEPASTE_HCOUNT) ; Load and increase Horizontal counter
inc a
ld (TILEPASTE_HCOUNT),a
cp 16 ; Compare 16 (maximum amount of tiles across the screen)


pop hl ; Restore counter (b) and map data (hl)
pop bc


jr nz, TILE_PASTE_LOOP ; Check if we've pasted 16 tiles across, and if so...
; ...do a vertical shift down and back to the left...
; ...hand side to start pasting the next row down. If not...
; ...then keep pasting horizontally.


push bc ; Save counter (b) and map data (hl) again
push hl
; VERTICAL SHIFT DOWN AT END OF ROW
ld bc,(TILE_XY)
xor a
ld b,a
ld (TILE_XY),bc ; Reset X paste coordinate 'b' (Back to left of screen)
ld (TILEPASTE_HCOUNT),a ; Reset H-count


ld a,&10
ld l,a
ld bc,(TILE_XY) ; Load into XY variable
ld a,c
add l ; Add 16 lines worth to Y-Coordinate to shift down
ld c,a
ld (TILE_XY),bc
xor a
ld b,a
ld (TILEPASTE_HCOUNT),a ; Reset Horizontal-counter


ld a,(TILEPASTE_VCOUNT) ; Load Vertical-counter to check
inc a
ld (TILEPASTE_VCOUNT),a
cp 12 ; Check to see if last (bottom)row is complete and reset


jr z, TILE_DRAW_RESET ; ...everything if it has before exiting to game loop.


pop hl ; Restore counter (b) and map data (hl)
pop bc
djnz TILE_PASTE_LOOP ; If we are not at the last row then go back to the start


TILE_DRAW_RESET: ; Background is done drawing. Now reset everything to draw again


ld bc, &0000 ; Clear counter
ld (TILE_XY),bc
xor a
ld (TILEPASTE_HCOUNT),a ; Reset Horizontal Counter
ld (TILEPASTE_VCOUNT),a ; Reset Vertical Counter
RET ; The screen has been drawn, so move on to rest of game code


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TILE AND TILEMAP VARIABLES & CONSTANTS ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


; TILESET_WIDTH_BYTES db 256/4 ; Width of entire tileset in bytes (320/4)
; TILESET_HEIGHT_LINES db 176 ; Height of entire tleset in lines
TILEMAP_WIDTH_TILES EQU &10
TILEMAP_HEIGHT_TILES EQU &0C
TILESET_NUMBER EQU 2


TILE_WIDTH db &04 ; 4
TILE_HEIGHT db &10 ; 16
TILE_SIZE EQU TILE_WIDTH*TILE_HEIGHT


TILE_XY dw &0000
TILE_WH dw &0410
TILEPASTE db 0
; Amount of tiles in tileset
; TILES_PER_SCREEN db 176 ; 16 x 11 (256 x 192) 16 x 16 tiles
TILE_LUT db 255
TILE_WHICH db 0


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TILE MAP ;;
;;;;;;;;;;;;;;


TILE_MAP:


defb &1,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1 ; ROW 1
defb &1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0 ; ROW 2
defb &0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1 ; ROW 3
defb &1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0 ; ROW 4
defb &0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1 ; ROW 5
defb &1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0 ; ROW 6
defb &0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1 ; ROW 7
defb &1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0 ; ROW 8
defb &0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1 ; ROW 9
defb &1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0 ; ROW 10
defb &0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1 ; ROW 11
defb &1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0,&1,&0 ; ROW 12




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; TILE BANK ;;
;;;;;;;;;;;;;


TILE_BANK:
dw T10,T11
RET


TILES:


T10: incbin "C:\AMSTRAD\GRAPHICS\LEVEL 1 TILES\0.RAW"
T11: incbin "C:\AMSTRAD\GRAPHICS\LEVEL 1 TILES\1.RAW"
RET


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DRAW ROUTINE ;;
;;;;;;;;;;;;;;;;;;


TILE_DRAW_ROUTINE: ; TILE_DRAW Start
ld de,(TILEPASTE)
TILEPOSITION:
push de
ld bc,(TILE_XY) ; Load X-POSITION
call GetScreenPos ; New plotting code
pop de
DRAWTILE_2SCREEN:
;ld bc,(TILE_WH)
ld a,(TILE_HEIGHT) ; Load sprite height value to 'a'
ld b,a ; Height (LINES)
Tilenextline: ; OUTER LOOP
push hl
;ld bc,(TILE_WH)
ld a,(TILE_WIDTH) ; Width (BYTES)
ld c,a ; Bytes per line
TileNextByte: ; INNER LOOP


ld a,(de) ; Source Byte
ld (hl),a ; Screen Destination
inc de ; INC Source (Sprite) Address
inc hl ; INC Dest (Screen) Address
dec c ; Repeat for next byte


jr nz,TileNextByte ; INNER LOOP END
pop hl
call GetNextLine ; Scr Next Line (Alter HL to move down a line)
djnz Tilenextline ; OUTER LOOP END ; Repeat for next line
RET ; TILE_DRAW Finished



Unlocking the dark arts of assembly!

Axelay


There's too much missing from that code for me to run it (two routines & some variables), so I can only provide a bit of a guess, but with just a quick look it appears you are using TILE_BANK_SCAN to set de as a pointer to an entry in TILE_BANK.  TILE_BANK is a list of 16 bit addresses and in each iteration of TILE_BANK_SCAN you are only incrementing de once, so every other iteration, de will not point to a meaningful address, as far as I can tell.  But you are loading hl with the contents of TILE_INDEX, which is not defined in your sample, so I can't be sure what role that serves, but since l is being compared to a it appears to be a straight tile number check.


A suggestion though, a loop like that would get slow with a large number of tiles.  If I've understood what that loop is trying to do (and maybe I haven't) and you just want de to point to the entry in TILE_BANK for your tile, rather than a loop it would be faster to use something like the following, unless there's a particular reason you need to use a loop:



ld de,TILE_BANK
ld l,a ; a has tile number
ld h,0 ; hl = tile number
add hl,hl ; hl = hl x 2 = tile address offset for TILE_BANK table
add hl,de ; hl = pointer to tile address in TILE_BANK
ex de,hl ; de now contains pointer to tile address in TILE_BANK

Kitsune Mifune


Thank you for the reply.


I didn't think when I cut that piece of code out to paste here that there may be stuff missing as it is part of a larger program, so apologies for that.


There's no real reason I've made it a loop, it was just the first thing that came to mind when I took a stab at it as I wanted to draw the background first then the players etc. You are right about TILE_INDEX. It's literally just a number used to compare with the time map number and that match would fetch the relevant tile.


I very much appreciate you taking time to do the code example so thank you again, and yes the very part you pointed out about TILE_BANK was what I was suspecting what was wrong, but I wasn't quite sure where to go with it.


This is my first attempt at doing anything like this and the help is invaluable, so thank you a third time, and I'll go try out that code now.
Unlocking the dark arts of assembly!

Powered by SMFPacks Menu Editor Mod