It is currently Tue Sep 25, 2018 11:26 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Metatile troubles
PostPosted: Mon Sep 16, 2013 10:03 am 
Offline

Joined: Tue Nov 20, 2012 1:59 pm
Posts: 67
I've tried several attempts at getting a working metatile loader thrown together with very little success. Anyway, I have this routine here that should be taking the contents of a map data string and copying what should go into the nametable into RAM. I've tried many methods for this and the current is what I like best because it's sleek and nice looking. Anyway, I've tried debugging it and I'm still unsure where it's happening, but it seems like something is getting overwritten because when I ran the program it's showing the signs of going into an infinite loop.

Here is the routine:
Code:
Scratch .rs 2         ;reserve 2 bytes for scratch
Buffer  .rs 64         ;reserve 64 bytes for level decompression
MetaTileData_Ptr  .rs 2       ;2 bytes for the pointer currently proccessed metatile
ColumnNumX_Ptr     .rs 2      ;2 bytes for column number
ColumnNumY_Ptr     .rs 2      ;2 bytes for column number
[...]
;$00
InitMap:
 LDY #$00
 LDA #$03      ;Pos of buffer
 STA ColumnNumX_Ptr
 LDA ColumnNumX_Ptr+32
 STA ColumnNumY_Ptr
LoadMap:
 LDA LevelData,y
 STY Scratch
 JSR WriteTileToBuffer   ;a = metatilenumber to process
 LDY Scratch
 INY
 CPY #$15
 BNE LoadMap
 RTS

WriteTileToBuffer:
 LDX MT_Table,y
 STX MetaTileData_Ptr
 LDA #HIGH(MT_Table)
 STA MetaTileData_Ptr+1
 LDY #$00         ;start at 0
 LDX #$00
 LDA [MetaTileData_Ptr],y   ;do 1
 STA [ColumnNumX_Ptr,x]
 INY
 INX
 LDA [MetaTileData_Ptr],y   ;do 2
 STA [ColumnNumX_Ptr,x]
 INY
 INX
 LDA [MetaTileData_Ptr],y   ;do 3
 STA [ColumnNumY_Ptr,x]
 INY
 INX
 LDA [MetaTileData_Ptr],y   ;and finally the 4th byte
 STA [ColumnNumY_Ptr,x]
 LDA ColumnNumX_Ptr
 INC A            ;\ We wrote 4 bytes so increase the ptrs accordingly
 INC A            ; |
 STA ColumnNumX_Ptr      ; |
 LDA ColumnNumY_Ptr      ; |
 INC A            ; |
 INC A            ;/
 STA ColumnNumY_Ptr
 RTS



Here are my tables:
Code:
MT_Table:
 .db LOW(MetaTileBlock00),LOW(MetaTileBlock01),LOW(MetaTileBlock02),LOW(MetaTileBlock03)

MetaTileBlock00:
  .db $23,$23,$23,$23
MetaTileBlock01:
  .db $20,$21,$30,$31
MetaTileBlock02:
  .db $22,$23,$32,$33
MetaTileBlock03:
  .db $01,$01,$01,$01
LevelData:
  .db $02,$02,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01,$01


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 10:23 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3610
Location: Mountain View, CA
Quote:
Code:
 LDA ColumnNumX_Ptr
 INC A            ;\ We wrote 4 bytes so increase the ptrs accordingly
 INC A            ; |
 STA ColumnNumX_Ptr      ; |
 LDA ColumnNumY_Ptr      ; |
 INC A            ; |
 INC A            ;/
 STA ColumnNumY_Ptr

I can tell you one thing: there is no INC A on the 6502 ("A" here is obviously a reference to the accumulator, not a variable or memory location that you've labelled "A") The assembler you're using is letting you use 65c02 or newer opcodes; the 6502 does not have a way to increment the accumulator aside from clc ; adc #1 (or in this case, you'd want to use clc ; adc #2 since you're wanting to add 2 to something).

Your INC A is probably being assembled into opcode $1a, which is an undefined opcode on the 6502, and is probably causing you chaos.

Get yourself an assembler that adheres strictly to 6502. :-)


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 12:34 pm 
Offline

Joined: Tue Nov 20, 2012 1:59 pm
Posts: 67
Okay, that makes sense. However, it is producing different results but still seems to go into an infinite loop. Anyone know why? :shock:


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 1:04 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 927
Location: cypress, texas
koitsu wrote:
INC A is probably being assembled into opcode $1a, which is an undefined opcode on the 6502, and is probably causing you chaos.


Yes, executing undefined instructions is really bad... probably the cause of your infinite loop.


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 1:45 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10819
Location: Rio de Janeiro - Brazil
You appear to be doing unnecessary complex pointer operations, and making lots of mistakes along the way. For example, I don't see you ever setting the high bytes of ColumnNumX_Ptr or ColumnNumY_Ptr, so when you use those pointers you'll hardly get the addresses you expect. Also, you have the index of the metatile you want to draw in A when you call WriteTileToBuffer, but then you trash it with the LDA #HIGH(MT_Table) command.

Still, errors aside, the solution you're trying to come up with is way more complicated than it should be. Is there any reason why you can't copy your tiles like this:
Code:
WriteTileToBuffer:
   tay
   lda MetaTileBlock00, y
   sta Buffer+0, x
   lda MetaTileBlock01, y
   sta Buffer+1, x
   lda MetaTileBlock02, y
   sta Buffer+32, x
   lda MetaTileBlock03, y
   sta Buffer+33, x
   inx
   inx
   rts

You don't need pointers unless you have more than 256 types of metatiles throughout the game, but even if you do you can use this exact same code, except you'd use indirect addressing instead of absolute addressing for accessing the 4 corners of the metatile (you have to setup the 4 pointers whenever the tileset changes, which is usually between levels):
Code:
WriteTileToBuffer:
   tay
   lda (MetaTileTopLeft), y
   sta Buffer+0, x
   lda (MetaTileTopRight), y
   sta Buffer+1, x
   lda (MetaTileBottomLeft), y
   sta Buffer+32, x
   lda (MetaTileBottomRight), y
   sta Buffer+33, x
   inx
   inx
   rts


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 2:11 pm 
Offline

Joined: Tue Nov 20, 2012 1:59 pm
Posts: 67
Quote:
,there any reason why you can't copy your tiles like this:

Yes. I'm not sure if I understand your code there. It's using the labels I've made just for readability. wouldn't that be hardcoding them? What I'm trying to say here is how would I use your code but instead of the "block 01" "block 02" ect loading make it load from the beginning of a long set of metatile data?

edit: also, using your method is only viable for one single metatile right? because there's nothing to stop the next jsr to that routine to keep overwriting itself


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 3:33 pm 
Offline
User avatar

Joined: Sun Jan 02, 2011 11:50 am
Posts: 522
Code:
 
STA [ColumnNumY_Ptr,x]


I doubt this is doing what you want, this is not the same as [pointer],y. There is nowhere in this code that needs pointers. Maybe if your metatile definitions were various sizes, you would need a pointer table to find the beginning of the metatile data.

You can leave your data as is and multiply the metatile(0 to 3) to by 4 to find the start index of the relevant data or arrange it so all top left, top right etc are together: (all $23 cause I'm lazy)

Code:
MetaTileBlock00: .db $23,$23,$23,$23 ; all top left
MetaTileBlock01: .db $23,$23,$23,$23 ; all top right
MetaTileBlock02: .db $23,$23,$23,$23 ; all bottom left
MetaTileBlock03: .db $23,$23,$23,$23 ; all bottom right


Then look at tokumaru's code again.


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 3:37 pm 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1244
zkip wrote:
Quote:
,there any reason why you can't copy your tiles like this:

What I'm trying to say here is how would I use your code but instead of the "block 01" "block 02" ect loading make it load from the beginning of a long set of metatile data?

Edited because Kasumi is very silly... :oops:
By changing the value in A.
This writes tile $00.
Code:
     lda #$00
     jsr WriteTileToBuffer

Code:
     lda #$0F
     jsr WriteTileToBuffer

This writes tile $0F.

I'm not sure what you mean that that will only write a single metatile. It will, but you put it in a loop to load the whole map. Something like:
Code:
levelloop:
     sty scratch
     lda leveldata,y
     jsr WriteTileToBuffer
     ldy scratch
     iny
     dec tilesleft
     bpl levelloop


I'm not sure what you mean by "there's nothing to stop the next jsr to that routine to keep overwriting itself".

edit2: Also, I probably misunderstood your first question:

Quote:
What I'm trying to say here is how would I use your code but instead of the "block 01" "block 02" ect loading make it load from the beginning of a long set of metatile data?


Currently, Tokumaru suggests this:
Code:
WriteTileToBuffer:
   tay
   lda MetaTileBlock00, y
   sta Buffer+0, x
   lda MetaTileBlock01, y
   sta Buffer+1, x
   lda MetaTileBlock02, y
   sta Buffer+32, x
   lda MetaTileBlock03, y
   sta Buffer+33, x
   inx
   inx
   rts

For the table you have:
Code:
MetaTileBlock00:
  .db $23,$23,$23,$23
MetaTileBlock01:
  .db $20,$21,$30,$31
MetaTileBlock02:
  .db $22,$23,$32,$33
MetaTileBlock03:
  .db $01,$01,$01,$01


If you needed more sets, he's suggesting you do this:
Code:
WriteTileToBuffer:
   tay
   lda (MetaTileTopLeft), y
   sta Buffer+0, x
   lda (MetaTileTopRight), y
   sta Buffer+1, x
   lda (MetaTileBottomLeft), y
   sta Buffer+32, x
   lda (MetaTileBottomRight), y
   sta Buffer+33, x
   inx
   inx
   rts


Say these are your tables:
Code:
;Yeah, they're all the same. Pretend they're different
;And long!
GrasslandsMetaTileBlock00:
  .db $23,$23,$23,$23
GrasslandsMetaTileBlock01:
  .db $20,$21,$30,$31
GrasslandsMetaTileBlock02:
  .db $22,$23,$32,$33
GrasslandsMetaTileBlock03:
  .db $01,$01,$01,$01

WaterlevelMetaTileBlock00:
  .db $23,$23,$23,$23

WaterlevelMetaTileBlock01:
  .db $20,$21,$30,$31

WaterlevelMetaTileBlock02:
  .db $22,$23,$32,$33

WaterlevelMetaTileBlock03:
  .db $01,$01,$01,$01


To use indirect code, MetaTileTopLeft etc now refer to RAM rather than ROM.
Code:
;MetaTileTopLeft (and MetaTileTopLeft+1) stores a 16bit address.

;To make it load from the grasslands set:
   lda #low(GrasslandsMetaTileBlock00);Not sure the syntax on your assembler
;But this loads the low byte of the address GrasslandsMetaTileBlock00
;Begins at
   sta MetatileTopLeft

   lda #high(GrasslandMetaTileBlock00);Same for High byte
  sta MetaTileTopLeft+1
;Do the same for the other 3 blocks

From there
Code:
   lda (MetaTileTopLeft), y
   sta Buffer+0, x

Would load the Grasslands data as you'd expect. If you write the address for the waterlevel block to MetatileTopleft etc, that same code will load the waterlevel data.

_________________
https://kasumi.itch.io/indivisible


Last edited by Kasumi on Mon Sep 16, 2013 4:47 pm, edited 5 times in total.

Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 3:56 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 927
Location: cypress, texas
Kasumi wrote:
This writes tile $00.
Code:
     ldy #$00
     jsr WriteTileToBuffer

Code:
     ldy #$0F
     jsr WriteTileToBuffer

This writes tile $0F.
How does WriteTileToBuffer write tile $0f? The first instruction is tay... that would copy the accumulator into y overwriting y. Right?


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 3:59 pm 
Offline
User avatar

Joined: Wed Apr 02, 2008 2:09 pm
Posts: 1244
That's true. My bad, so you'd load A with the tile you want instead of Y.

_________________
https://kasumi.itch.io/indivisible


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 4:23 pm 
Offline

Joined: Tue Nov 20, 2012 1:59 pm
Posts: 67
Man this is confusing lol..... I guess I should have worded that better. I don't have separate banks of metatiles. Just one. No separate tileset..just the one. What i don't understand is in your code your lda'ing with all of the block labels. why? I was under the assumption that all one needed to do was supply the starting address of the metatiles data.

edit: say those labels weren't there. Could I just make a big table of the metatile data and make just one label?


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 4:35 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10819
Location: Rio de Janeiro - Brazil
zkip wrote:
Yes. I'm not sure if I understand your code there.

Fair enough, you shouldn't use code you don't understand (don't ever copy/paste chunks of code together hoping they'll work if you don't understand the purpose of each chunk), but that's also not a reason to go for a solution way too more complex for your problem, specially if it's getting out of hand like in this case.

Quote:
It's using the labels I've made just for readability.

Not at all. The subroutine I wrote is indeed not a direct replacement of yours, but it's close enough. The only thing missing is the initialization of the X register, which has to be set to 0 before the decoding loop begins (since there is no pointer being updated anymore). Something like this (adding to what kasumi wrote):
Code:
   ldx #$00 ;star filling the buffer from 0
levelloop:
   sty scratch ;backup Y
   lda leveldata, y ;get the index of the metatile
   jsr WriteTileToBuffer ;decompress it to the buffer
   ldy scratch ;restore Y
   iny ;go to the next metatile
   cpx #$20 ;is the buffer full yet?
   bne levelloop ;if not, get another metatile


Quote:
wouldn't that be hardcoding them? What I'm trying to say here is how would I use your code but instead of the "block 01" "block 02" ect

With a loop similar to the above, like Kasumi said.

Quote:
edit: also, using your method is only viable for one single metatile right? because there's nothing to stop the next jsr to that routine to keep overwriting itself

The value in X is kept between calls to the function, so nothing is overwritten.

zkip wrote:
Man this is confusing lol..... I guess I should have worded that better. I don't have separate banks of metatiles. Just one. No separate tileset..just the one.

Then forget about pointers altogether, you really don't need them for this.

Quote:
What i don't understand is in your code your lda'ing with all of the block labels. why?

Because you need to load the four corners of the metatile, so we have one LDA instruction for each corner.

Quote:
I was under the assumption that all one needed to do was supply the starting address of the metatiles data.

Not necessary unless you have more than 256 metatiles. The index register (n this case, Y) can address up to 256 values, so if it contains #$05 and you do LDA MetaTileBlock00, y, that means "get the top left tile of metatile number $05". That will work up until metatile number 255, after that you'll need pointers.

You will maybe need pointers to read from your level map though, unless they're all < 256 metatiles (which could be the case if there's no scrolling, since you need 240 metatiles to fill the whole screen).


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 5:14 pm 
Offline

Joined: Tue Nov 20, 2012 1:59 pm
Posts: 67
Please forgive my abundance of question asking, and my un-ability to grasp this concept, but I still don't get it. :E

Quote:
The index register (n this case, Y) can address up to 256 values, so if it contains #$05 and you do LDA MetaTileBlock00, y, that means "get the top left tile of metatile number $05". That will work up until metatile number 255, after that you'll need pointers.


I understand this, but the way the labels are being used is confusing me. Say I've got 16 metatiles instead of the 4 we have now. MetaTileBlock00-MetaTileBlock10 in order. Now what? Would the routine still be effective? If so, why are only the first 4 corner offsets loaded? (edit: I know 4 tiles make up a 16x16 tile, but why load the first 4 labels instead of say the last 4 or middle 4?)


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 5:47 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10819
Location: Rio de Janeiro - Brazil
zkip wrote:
I understand this, but the way the labels are being used is confusing me. Say I've got 16 metatiles instead of the 4 we have now. MetaTileBlock00-MetaTileBlock10 in order. Now what?

Oh, now I get why you're confused! Each label in your table represents a metatile, I assumed that each label represented a corner of the metatiles... The code I posted assumed the data was arranged like this:

Code:
TopLeftTile: .db $00, $01, $02, $03, $04, $05, (...)
TopRightTile: .db $20, $21, $22, $23, $24, $25, (...)
BottomLeftTile: .db $60, $61, $62, $63, $64, $65, (...)
BottomRightTile: .db $80, $81, $82, $83, $84, $85, (...)

Which means that metatile #0 is made of the following tiles: $00, $20, $60, $80. I often arrange data like this because the 6502 is better at reading structures of arrays rather than arrays of structures. In this case, even if you have 200 tiles or more you'll still have only 4 labels in the code, because they represent the corners, and all metatiles have 4 corners.

You can do it your way and store the metatiles linearly, but then you can only have 64 of them before you need to use pointers. To read linear metatiles, my routine would look like this:
Code:
WriteTileToBuffer:
   asl ;multiply by 4 because each metatile uses 4 bytes
   asl
   tay ;use this as an index into the array of metatiles
   lda MetaTiles+0, y ;copy top left tile
   sta Buffer+0, x
   lda MetaTiles+1, y ;copy top right tile
   sta Buffer+1, x
   lda MetaTiles+2, y ;copy bottom left tile
   sta Buffer+32, x
   lda MetaTiles+3, y ;copy bottom right tile
   sta Buffer+33, x
   inx ;increment the output index by 1 metatile horizontally
   inx
   rts

Like I said, this can only access 64 metatiles, which is why I prefer the other method (which is a better option than using pointers, because it's simpler and faster).


Top
 Profile  
 
 Post subject: Re: Metatile troubles
PostPosted: Mon Sep 16, 2013 6:13 pm 
Offline

Joined: Tue Nov 20, 2012 1:59 pm
Posts: 67
Ah! Now I see. As I'm not planning on using very many metatiles at all. This seems to be perfect for my style. Thank you very much tokumaru. :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group