Arrays of structs? (a struct that defines a metatile, and have an array of them)Struct of arrays? (an array of top-left tiles. an array of top-middle-left tiles. and so forth)

I can see pros and cons of different methods, but curious what everyone else likes. I'm playing with the idea of using 4x4 tile metatiles for an in-progress game, and am playing with options now, but figure some of y'all might have some good advice about what's worked well or hasn't worked well for you in the past. I'm leaning towards the struct of arrays, as that's often the right answer on the 6502, but curious if others have thoughts or experiences that I might not have thought of.

I'm a big fan of structures of arrays. There's no simpler/faster way to access up to 256 items than with structures of arrays. Also, if you need to add more fields, just create new arrays without the need to modify the existing code/data.

I've used both. In simple cases arrays, in a more complex one where metatiles were made of metatiles and had collision + color info too, there I used an array of structures and a LUT for the multiplication for quick access.

Then in a third case I had arrays, but as they were big I added a skiplist of pointers.

Arrays of structs? (a struct that defines a metatile, and have an array of them)Struct of arrays? (an array of top-left tiles. an array of top-middle-left tiles. and so forth)

First of all, don't use an array of a struct. This counts for everything, not just for meta tiles.Always use structs with arrays in them instead, even if it makes less logical sense.

Because accessing a struct inside an array means that the CPU has to do two runtime calcuations:The address of the array item (if it's a variable like array[index].Value).And from that address, the address of the desired struct property.

If you use a bunch of arrays inside a struct, you only have one runtime calculation: The array offset. Because if your struct is a global variable, then the address of each property/array inside it is known at compile time.

Now to your actual question:

It depends on whether you're talking about metatiles of background or of sprites.

In my first game, I simply stored meta sprite definitions by specifying the height (width was hardcoded to 2 tiles, but you could of course also store the width) and the color palette (hence one palette per meta sprite) and then writing each tile number right after another. I.e. simple arrays.

So, in my game, the tiles were always aligned to 8 x 8 pixels, I didn't do arbitrary placement.

For the next game, I'll do it a bit differently:

I simply store the width and the height and the first tile index.

From there, it is a rule that the tiles for the meta sprite have to be in CHR in order.

Disadvantage: You cannot reuse duplicate tiles from CHR. If a certain sprite tile in two meta sprites looks identical, you have to store them twice in CHR. (In this case, it's not so bad since I use UNROM with CHR RAM while my first game was NROM where I only had 256 tiles for the whole game.)

Advantage: No matter how big your character is and no matter how many animation phases it has, you only need to store width, height and one tile index. That's it. (O.k., maybe some palette data, but one byte can be used for the palette values of four tiles.)

About the background:

In my new game, I use meta tiles for objects: Width, height, palette and all tiles in an array.

Then I have an array that stores all the addresses of the meta tile arrays.

And a single screen consists of a bunch of meta tiles: x position, y position and the index of the array that contains the array addresses.

(Just typing off what I remember - to be verified one I'm at home and I have access to the actual code).EDIT : This post is almost entierely wrong - proof that I don't even remember how I coded my game engine all those years ago

My game engine works with meta-metatiles, a 32x32 meta-metatiles is made of four 16x16 metatiles, which are made of 4 tiles. The smaller metatiles themselves are just here to gain ROM space in the meta-metatile definition, I could use 16-tiles metatiles directly but it would be more ROM wasting.

Each meta-metatile definition is 6 bytes, 4 for metatiles access, one byte for colour (gets copied "directly" to attribute table, or is split into two nybbles when necessary, depending on alignment), and one byte for collision.

There is basically no advantage of the "array of struct" method, except that it is humanly more intuitive. Only if the array is a power of two and if you already need to shift the value anyway then it doesn't add additional cost to 6502 asm code reading the data. As such, I originally used "array of struct" because it was more intuitive but eventually optimized into "struct of arrays" in order to save ROM.

Collision is single-bit and on 16x16 area, however it is very gross so I'm thinking about improving it to 8x8 area, if possible. Either that or keep 16x16 but support diagonal slopes.

Quote:

It depends on whether you're talking about metatiles of background or of sprites.

"Metatiles" always refers to background, the term used when compounding sprites is "metasprite". So half of your post was off-topic.

Last edited by Bregalad on Tue May 30, 2017 2:46 am, edited 1 time in total.

Oh, about collision: I'm using an array with 240 (16 x 15) entries since all meta tiles have to have an even number of tiles in width and height anyway and since each meta tile has to be aligned to 16 pixels on the screen (with an eight pixels alignment, the palette assignment wouldn't work).

With this array, I can check whether the character can walk to a certain location from his current location.

I might change the array to 30 entries (240 / 8) if required RAM space gets too big, but in the moment, I'm still fine storing the status values one byte per 16 x 16 square and therefore saving ROM space for not needing to do bit shifting whenever the array is accessed.

There is basically no advantage of the "array of struct" method, except that it is humanly more intuitive. Only if the array is a power of two and if you already need to shift the value anyway then it doesn't add additional cost to 6502 asm code reading the data. As such, I originally used "array of struct" because it was more intuitive but eventually optimized into "struct of arrays" in order to save ROM.

When your data has more than 256 entries, an array of structures has an advantage for serial access. (Both better speed and code complexity.)

Otherwise, yes, the only other advantage is to do with code organization, though that is a valid advantage too. (Worse speed and code complexity, but often easier to read/type the array data as assembly or C code.)

When your data has more than 256 entries, an array of structures has an advantage for serial access. (Both better speed and code complexity.)

The only other advantage I can think of is for iterating through the different actual-tile definitions in the metatile definition. If it's an array of structs, once you find the base address of the metatile you want, it's trivial to lookup or iterate through any of the 16 actual-tiles within it. Otherwise, for a struct of arrays, going from looking up tile[3,2] to looking up tile[3,3] isn't quite as trivial.

That said, I still think (like most of you are saying) that a struct of arrays is the right answer. Thanks for your thoughts!

Here's some actual map data from my current game. Just like suggestions above, it's all structures of arrays. (except for the row_offsets array, that's just an array of words with row offsets typically used for horizontal maps, but also for horizontal transitions into vertical maps) It's a pretty simple format where I've got "big metatiles" which are full 32x32 pixel sized chunks which contain regular "metatiles" which are just 16x16 pixels or a square containing 4 nametable tiles. Each metatile has additional metadata such as the color attribute, and properties which is a bitfield with information about which direction to eject the character and an action to perform, if any.

I have five byte arrays to store each one of the 4 patterns in every metatile (2x2) plus the palette used. I have a sixth byte array to store each metatile behaviour (obstacle, platform, water, lava, slippery surface, etc). Behaviours are bit-mapped and can be combined. Each metatile always have the same behaviour. I never needed more complexity, and this makes my engines fast and tight, considering I'm a C coder.

Maps, once unpacked, are a series of indexes to all those arrays. Lately I've been using simple 4.4 or 3.5 bits RLE.

I use this arrangement for flick screen or scrolling games whenever I use 2x2 metatiles.

Some years ago i was a bit suprised to see (from snowbro's disassembly) that metroid organized properties tile-level, seeing that it's never used on anything other than one singular two structures (the spawning pipes & lava spitters). they could just aswell have done without it. But it's good for level hacks, with a small fix in the collision detection.

When loading a map, I do some bitwise shenanigans (0,1,0,1,0,1... 2,3,2,3,2,3...), to keep track of which attribute quadrant I'm on, zeroing out the upper 6 bits, before using both the quadrant number, and the palette index, to read the pre-shifted values from a table.

This sacrifices 13 cycles per iteration, and only uses 16 bytes for a table, instead of (potentially) up to 256 bytes of potentially wasted ROM space. I'd rather use that space for maps/music. At least for an NROM game.

(This trick may have been devised, by working on the VCS hardware, with more extreme restrictions.)

So I just checked how my game did it, and actually it doesn't do what I mentionned at all

To define a 32x32px metatile, I use the "evil" array-of-structure scheme, with each structure being 5 bytes. The reason I never switched to structure-of-array is that this wasn't necessary. I copy the definitions from ROM (in this case, CHR-ROM) to RAM, and I change it to an "structure of array" during this operation. As such, when I'm either rendering a screen or checking collision, I just use values in RAM and I don't have to worry in which stage I am, to read the appropriate table. This simplifies the runtime code greatly.

The first byte correspond directly to the value written to the attribute table. (Except in some alignements where it might be separated between 2 nibbles). Then the next 4 bytes are references to 16x16 intermediate metatile indexes, and the 7th bit is used for collision, so that if the value is negative they are walkable and if it's positive they are unwalkable. The 6th bit seems unused (I never use more than 64 16x16px metatiles) so in theory I could use it for improving collision, how exactly I don't know.

The 16x16 intermediate metatiles are defined separatedly, and use 4 consecutive bytes to define metatiles. As thus, I never use the "structure-of-arrays" scheme.

Who is online

Users browsing this forum: No registered users and 7 guests

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