storing metatiles and their order

Are you new to 6502, NES, or even programming in general? Post any of your questions here. Remember - the only dumb question is the question that remains unasked.

Moderator: Moderators

Post Reply
User avatar
Kitty_Space_Program
Posts: 50
Joined: Mon Sep 21, 2020 7:42 am

storing metatiles and their order

Post by Kitty_Space_Program » Mon Dec 07, 2020 10:32 pm

So I'm trying to learn how to store metatiles, and I've got them all written out like so:

Code: Select all


ground:
  .db $ef, $f0;first row
  .db $f0, $ef;second row
  .db $00 ;pallete
sky:
  .db $f1,$f1
  .db $f1,$f1
  .db $02
rock:
  .db $f1,$f1
  .db $f1,$f2
  .db $02
  
  
and I'd like to be able to organize my levels with .db and reference each of the tiles with a number, but I can't figure out a way to do so. My best guess is to have a byte array of 0, 5, a, &c. or split them up into 2 or three sections (where palletet and possibly the second row are stories separately, but both of those seem a bit unwieldy. Any ideas? I'm completely lost here. Thank you!

User avatar
tokumaru
Posts: 11996
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: storing metatiles and their order

Post by tokumaru » Tue Dec 08, 2020 1:00 am

The 6502 is pretty bad at accessing arrays of structures like you have there... The most common solution is to use structures of arrays instead:

Code: Select all

TopLeft:
	.db $ef, $f1, $f1
TopRight:
	.db $f0, $f1, $f1
BottomLeft:
	.db $f0, $f1, $f1
BottomRight:
	.db $ef, $f1, $f2
Palettes:
	.db $00, $02, $02
This way you can use index 0 for ground, index 1 for sky, and index 2 for rock. If you need to automate this a bit so you have more freedom to move stuff around without breaking anything, most assemblers should let you use placeholders in the table and assign values elsewhere:

Code: Select all

TopLeft:
	.db M0T0, M1T0, M2T0, M3T0, ...
TopRight:
	.db M0T1, M1T1, M2T1, M3T1, ...
BottomLeft:
	.db M0T2, M1T2, M2T2, M3T2, ...
BottomRight:
	.db M0T3, M1T3, M2T3, M3T3, ...
Palettes:
	.db PAL0, PAL1, PAL2, PAL3, ...

Code: Select all

rock = 3
M3T0 = $f1
M3T1 = $f1
M3T2 = $f1
M3T3 = $f2
PAL3 = $02
This works even better if your assembler supports macros that can manipulate labels, like ca65 does. Then you can create one macro to generate the placeholders for you, and another macro to fill in the values for each metatile and "return" their index through a symbol. Creating metatiles could then look something like this:

Code: Select all

	CreateMetatileSet 42 ;reserves space for 42 metatiles
	RegisterMetatile $f1, $f1, $f1, f2, $02, rock ;assigns values to placeholders, copies index to "rock" and increments index
	RegisterMetatile $ef, $f0, $f0, $ef, $00, ground
	;(...)
Macros can make things very readable and easy to edit, while still outputting data in a format that's friendly for the CPU to use. In an assembler like ca65 you can go really crazy with your macros.

User avatar
Kitty_Space_Program
Posts: 50
Joined: Mon Sep 21, 2020 7:42 am

Re: storing metatiles and their order

Post by Kitty_Space_Program » Tue Dec 08, 2020 1:08 am

Great, thank you. I would have never thought to do it like that lol. I’ll try that out tomorrow.

User avatar
tokumaru
Posts: 11996
Joined: Sat Feb 12, 2005 9:43 pm
Location: Rio de Janeiro - Brazil

Re: storing metatiles and their order

Post by tokumaru » Tue Dec 08, 2020 1:39 am

Let us know how it goes.

BTW the same "rules" apply to several other types of data, such as object states: instead of using contiguous sections of RAM for storing the state of each object, it's better to have separate arrays for each attribute that objects have. Something like this (ca65 syntax):

Code: Select all

MAXOBJECTS = 16
ObjectType: .res MAXOBJECTS
ObjectXLow: .res MAXOBJECTS
ObjectXHigh: .res MAXOBJECTS
;(...)
Then you can easily loop through the active objects using an index register, where index 0 is used to access the properties of the first object, index 1 the properties of the second object, and so on. Every game engine I've ever seen in 6502 does it like this.

Whenever you can use parallel arrays in 6502 code, which's usually the case when the sizes of the structures is constant (e.g. all metatiles are the same size), do it. It's always easier and faster to access data using indexing in increments of 1 than to use dynamic pointers, multi-byte increments, and the like.

User avatar
Kitty_Space_Program
Posts: 50
Joined: Mon Sep 21, 2020 7:42 am

Re: storing metatiles and their order

Post by Kitty_Space_Program » Tue Dec 08, 2020 3:49 pm

tokumaru wrote:
Tue Dec 08, 2020 1:39 am
Let us know how it goes.
It went really well, especially considering there wasn't any tutorial lol. It took about 200 lines of assembly code for both nametables, I assume that's a lot, but it works. *knocks on wood*

Post Reply