Attributes with 32x32 Metatiles

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

Roth
Posts: 400
Joined: Wed Aug 03, 2005 3:15 pm
Contact:

Attributes with 32x32 Metatiles

Post by Roth »

I am working on a 32x32 metatile background engine, but started thinking about this when I started making some dummy data to test with. Would it be better to store the attribute byte with the metatile, or separate from it? As an example, if I were to store it like this:

Code: Select all

; 32x32 metatiles = tile_name: four bytes for 16x16 metatiles and one byte for the attribute table
tile32_000:
	.byte $00,$00,$00,$00,$00
tile32_001:
	.byte $01,$02,$00,$00,$00
tile32_002:
	.byte $00,$00,$01,$02,$00
... I would then have the attribute attached to the end of each tile. There is also the option of this:

Code: Select all

screen_00:
	.addr tile32_001, tile32_001, tile32_001, tile32_001, tile32_001, tile32_001, tile32_001, tile32_001
	.addr tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000
	.addr tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000
	.addr tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000
	.addr tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000, tile32_000
	.addr tile32_002, tile32_002, tile32_002, tile32_002, tile32_002, tile32_002, tile32_002, tile32_002
screen_00_attrib:
	.byte $00, $00, $00, $00, $00, $00, $00, $00
	.byte $00, $00, $00, $00, $00, $00, $00, $00
	.byte $00, $00, $00, $00, $00, $00, $00, $00
	.byte $00, $00, $00, $00, $00, $00, $00, $00
	.byte $00, $00, $00, $00, $00, $00, $00, $00
	.byte $00, $00, $00, $00, $00, $00, $00, $00
I'm starting to think that maybe I should store them separate, because there is the possibility of compressing the attributes. I don't know which is really more beneficial, or if I'm overlooking anything. Any thoughts?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

SMB1 does it the first way, but it hardcodes the attribute number as equal to the upper two bits of the metatile number.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

It sure is nice to work with 32x32 metatiles so that you can store the attribute bytes already formed, it pretty much eliminates the complexity of messing with attribute bits. If you scroll vertically you still have to deal with nibble manipulation, but I don't think this is your case.

Anyway, I think it's best to keep the attributes as part of the information of metatiles. If you stored them separately for each screen, you'd be storing a lot of repeated information, because you would have to specify the exact same attribute byte for each instance of the metatile that uses it, something that would probably kill the gains from any compression scheme you used.

If you think about it, making that information part of the metatiles *IS* a form of compression. Instead of repeating certain combinations of attribute bits over and over you are assigning them to the blocks that commonly use them. If you have 256 metatiles, there will be 256 attribute bytes. That same space would only be enough to represent 4 raw attribute tables. So if your level has more than 4 screens you are already wasting space that way.

You will probably save a lot of space by compressing the metatile layout for each screen though.
Roth
Posts: 400
Joined: Wed Aug 03, 2005 3:15 pm
Contact:

Post by Roth »

tokumaru wrote:... you would have to specify the exact same attribute byte for each instance of the metatile that uses it, something that would probably kill the gains from any compression scheme you used.
Yeah, that would eat up more space. Sounds like attaching it to the metatile is the best way to go. Thanks!

That's an interesting way to do the attributes in SMB1. It seems like that would be something you would do if you knew you had xx amount of metatiles to deal with from the get go (design stage of development!). Does anyone know how many metatiles it has total?
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

SMB1 has fewer than 256 metatiles and fewer than 64 metatiles with each attribute value. This means it can use four metatile to hardware tile tables, one for each attribute value, each shorter than 256 bytes. (Source: Doppelganger's disassembly)
ProgrammingAce
Posts: 36
Joined: Sun Mar 29, 2009 4:04 pm

Post by ProgrammingAce »

I was thinking of using a method down the road that went like this:

Since under most circumstances there can only be 4 palettes, as long as you have less then 64 meta-tiles total you can steal 2 bits from each byte to assign the palette.

so if i had "%01000001", the first 2 bits are the attribute data (palette 2), the next 6 bits assign the tile as meta-tile number 1. Use a bitmask to split the byte.

As long as you have less then 64 meta-tiles, your attributes are "free" (minus the code to split them).
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad »

I don't think there is a correct or wrong way to do it. It's often a trade between compact and flexibility.[/img]
Useless, lumbering half-wits don't scare us.
Roth
Posts: 400
Joined: Wed Aug 03, 2005 3:15 pm
Contact:

Post by Roth »

For sure, you're right Bregalad! It's always nice to see other perspectives and ideas though, of course.

I was just laying in bed (long night last night) and had a thought. The way I have it set up now, I have two bytes for each address for each 32x32 tile. I basically did this so it wouldn't matter if I happened to go over 256 metatiles for some reason. What if instead, I employed the technique that Tokumaru showed me when we were discussing 16x16 metatiles? I could cut the size of each screen in half! I suppose if I thought I was going to go over 256 tiles, I could employ some sort of jump table that decides which batch of tiles to use (so they'd be grouped):

Code: Select all

; rocky tiles
; 00-transparent tile, 01-right rock, 02-left rock
rocky_a:
	.byte $00, $00, $02 ; etc.
rocky_b:
	.byte $00, $01, $00 ; etc.
rocky_c:
	.byte $00, $00, $02 ; etc.
rocky_d:
	.byte $00, $01, $00 ; etc.
rocky_attribute:
	.byte $00, $55, $55 ; etc.

; watery tiles
; 00-left wave, 01-right wave
watery_a:
	.byte $01, $04 ; etc.
watery_b:
	.byte $00, $05 ; etc.
watery_c:
	.byte $01, $06 ; etc.
watery_d:
	.byte $00, $07 ; etc.
watery_attribute:
	.byte $65, $56 ; etc.
... and this would make a seemingly endless supply of metatiles. The RTS trick would decide which ones to point at I guess:

Code: Select all

rocky_tiles_choice:
	lda #<rocky_a
	sta pointer_a
	lda #>rocky_a
	sta pointer_a+1
	lda #<rocky_b
	sta pointer_b
	lda #>rocky_b
	sta pointer_b+1
	lda #<rocky_c
	sta pointer_c
	lda #>rocky_c
	sta pointer_c+1
	lda #<rocky_d
	sta pointer_d
	lda #>rocky_d
	sta pointer_d+1
	lda #<rocky_attribute
	sta pointer_attribute
	lda #>rocky_attribute
	sta pointer_attribute+1
	rts

; similar code for other sets of tiles (since it would be the same code used over and over for each, maybe there will be some crazy way I can reuse the code or something)
I think that would work okay. Of course the whole jump table thing would only have to be deployed if I happened to go over 256 metatiles. But, I definitely like the idea of trimming down the tile data for each room from 192 bytes to just 96 bytes!
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad »

What I have for my game, and I think it is pretty much optimal, altough I might be wrong, is as follows :
I have 32x32 metatiles which are made of 4 16x16 metatiles, attribute data and collision data for each 16x16 metatile. There is 32 16x16 metatiles, the first 16 are customizable, while the last 16 are hardcored tile values (I did that to save ROM space as much as I could). So it is 4 bits * 4 for metatile #, 1 bit * 4 for selecting between hardcored or customizable metatile, 4 bits for collision and 8 bits for attribute which makes a great total of 4 bytes for a 32x32 metatile.
Although it's just my system - color and collision data comes with the 32x32 block itself, not with the 16x16 blocks it uses - it might sound weird but I think it makes it more compact, although I haven't made complex analysis of it.
Useless, lumbering half-wits don't scare us.
User avatar
tokumaru
Posts: 12106
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Post by tokumaru »

Roth, it seems you have described exactly what I do in my game. For each level I define a set of pointers indicating where to get the block data from. This allows for 256 metatiles per level, which should be enough. But even if it isn't, nothing prevents me from changing the pointers halfway through the level, as long as the blocks that are on screen at the time are defined in both sets.

In fact I could easily do what they do in Sonic 3 (& Knuckles), where there are no cuts between acts, each act is like a direct continuation of the previous. All I'd have to do is draw the place/room where the transition happens to both level maps, and adjust the positions of the objects (including the camera) to put them in the new place/room when the pointers to level data are changed. I could even do this seamlessly to create insanely large levels. I don't think I will though! =)
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

For my current project which doesn't scroll vertically, I do something similar to what has been described with 32x32 pixel tiles made of 4 16x16 metatiles. But instead of using 32x32 pixel metatiles, I use 64x16 pixel metatiles, which are still made of 4 16x16 metatiles. I assign collision information to the 16x16 tiles, but I assign attribute information to the 64x16. In my experience, it is much better to assign the attribute information to the 32x32 or 64x16 pixel metatiles, mainly because it saves space and time because it's simple. Also you may find you have more versatility since you can choose to color any 16x16 metatile whatever you want; you don't have to define another 16x16 metatile just so you can have a different color.

Also, I thought I should point out a good reason for using 64x16 metatiles instead of 32x32. The reason I decided to go with 64x16 rather than 32x32 is because of my screen size and the fact that I don't scroll vertically. The status bar takes up 32 pixels on the top of the screen, meaning 240 - 32 = 208 pixels of screen height is left, which isn't divisible by 32 pixels (so only half of the bottom 32x32 metatile would be displayed). It actually saves 4 bytes per screen definition to use my sized tiles, since each screen is made of 52 64x16 metatiles rather than 56 32x32. And to make things better, it is MUCH easier to define general purpose 64x16 metatiles than it is to define general purpose 32x32 metatiles. Though it does make updating attributes more complicated, it's a sacrifice I'm willing to make for saving space and making level design easier.
User avatar
Bregalad
Posts: 8036
Joined: Fri Nov 12, 2004 2:49 pm
Location: Caen, France

Post by Bregalad »

Well 64x16 metatiles sounds weird to me, but if it works for you why not.
My status bar is also 32 pixels tall, but there is also 16 pixels of overscan, which makes it 6 rows altogether, I'm left with 24 rows of tiles which make a screen 8x6 32x32 metatiles.
Useless, lumbering half-wits don't scare us.
User avatar
Dwedit
Posts: 4470
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

Rygar used vertical strips of 16x16 metatiles, so weird shapes aren't really that weird.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
tepples
Posts: 22345
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Post by tepples »

Dwedit wrote:Rygar used vertical strips of 16x16 metatiles
The Legend of Zelda used vertical columns as well.

Another technique is to make a special short code for the metatile that's most likely to be below a given metatile. For example, you could set up a table
sky -> sky
grass -> dirt
dirt -> dirt
water surface -> water below surface

Then you can encode a column of "sky, sky, sky, grass, dirt, dirt" as "sky, follow, follow, grass, follow, follow".
Celius
Posts: 2159
Joined: Sun Jun 05, 2005 2:04 pm
Location: Minneapolis, Minnesota, United States
Contact:

Post by Celius »

Well I guess 32x32 metatiles are better for screen-at-a-time games like Zelda or other top-down games like it. I can't really pinpoint why it is, but I just had a really hard time trying to reuse 32x32 tiles in my side scroller. Oh! I also know why I used 64x16 metatiles. My levels are made of 13 rows of tile data, and each row can be 256 metatiles long. Since my game scrolls only horizontally, making the tiles 64x16 allows me to have levels up to 64 screens long rather than 32, which is what my limit would be if I used 32x32 metatiles. I guess though that I'm never going to have a level that's 64 screens long, as this is an NROM project and that would take up a lot of space just for one level. I also plan to have action on each screen make up for small levels.
Post Reply