This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Map data formats

Map data formats
by on (#142445)
I want to rewrite my map scrolling code, so I have been thinking about what kind of data format to use for the maps. The old format I used was sort of lazy: 16x16 pixel metatiles in a flat table. This time I'd like to go for something better. If any of you have any thoughts on the topic, please share them.

Some design goals/constraints:

- Should be generic rather than limited. I don't mind losing a little bit in efficiency (in space and time) due to this. No object based formats like used in SMB1.
- Should work with multi-directional scrolling.
- Shouldn't needlessly limit artistic freedom (no "64 metatiles should be enough for everybody").
- Should be able to store a variety of extra info for tiles, such as 1) color attribute 2) slope type 3) collision flags
- Should not depend on extra cartridge RAM (but should be able to work with maps decompressed to WRAM).

There are so many options available I'm having hard time coming up with anything concrete, because I don't have a good grasp on the benefits/drawbacks of things such as:

- Metatile size (32x32 pixels? 16x16 pixels? Metatiles of metatiles?)
- Divide the map to screens of e.g. 256x256 pixels? (This seems like a good idea, so that sparse maps can be supported efficiently by having a map of screens. I guess "screen" here is really nothing but another name for a big metatile of metatiles.)
- Should attribute data be stored in metatiles, or should there be a separate map for them? Same goes for collision data. (Many, many options here. E.g. if we use 32x32 pixel metatiles which consist of 16x16 pixel metatiles, we could store attributes in the either metatile, or separated so that the same metatile could be used in two places with a different palette, for example).
- Maximum number of metatiles? 256 is a natural limitation to use here, but how likely are artists to run out of metatiles, say at the 16x16 pixel metatile level?

Existing solutions in games:

- Blaster Master apparently uses 256x256 pixel metatiles (screens), consisting of 64x64 pixel metatiles, consisting of 32x32 pixel metatiles, consisting of 16x16 pixel metatiles. I may have been misinterpreting the document I found, but it's something similar. The color attribute is associated with the 16x16 metatile.
- Gimmick uses 16x16 pixel metatiles. The whole map is stored more or less as is. The map is divided to screens, but the screens are not used to reduce redundancy. See my earlier post for some more info.
- Kirby uses 16x16 pixel metatiles and 256x192 pixel screens. Maps are stored compressed in ROM and decompressed to WRAM.
- <add your favorite game here>

Thoughts?

EDIT: Added an extra constraint about not requiring WRAM.
Re: Map data formats
by on (#142448)
I once made an engine that did 8x8 blocks (quarter screen) of 16x16 tiles, and a big 16x16 map of those 8x8 blocks. I did sort-of RLE compression (either run lengths, or run lengths taken from one row above) on the 16x16 big map. This limits you to levels 2048x2048 pixels large.
Re: Map data formats
by on (#142449)
Definitely divide into something large like screens. I divide into screens, but while typing up this post, I actually think 128x128 metatiles would be super cool.*

Definitely store attribute data with metatiles. (I don't think you'll have many metatiles that are identical except for their palette. Having a separate map would mean storing LOTS of redundant data whenever that's not true which is certainly the more common case.)
Definitely store collision info with metatiles. (Same as above. Is storing it separately likely to save you more space than having two of the same metatile with different collision info sometimes? Unless you mean define an arbitrary slope outside the metatiles so that multiple tiles can use it. In which case, yes, do that.)

As far as which metatile size gets this data, I'd say always the smallest one possible. You're likely to have larger (say... 32x32) metatiles that have very slightly different arrangements of smaller (say... 16x16 metatiles) metatiles. You only save space if each small metatile is used fewer than 4 times in the large ones.

Quote:
- Maximum number of metatiles? 256 is a natural limitation to use here, but how likely are artists to run out of metatiles, say at the 16x16 pixel metatile level?

The artists should be willing to meet you halfway, here. I would not go out of my way to support more than 256 of anything. (Err... but to actually answer your question, pretty likely if they don't know a lot. They're even likely to run of regular 8x8 tiles, which I see a lot a lot a lot.)

I chose 32x32 metatiles as my second largest size, because you can fit 4 screens of them in a page of RAM. Having 512x512 pixels covered in RAM is super nice for a multidirectional scroller. I really, really recommend 32x32 tiles specifically, with some larger size to make it easy to seek through the level. (Screens or whatever)

*So... I'm currently using 256x256 screens made of 32x32 metatiles made of 16x16 metatiles. I did it so I could fit 4 screens in RAM as mentioned above. However I have a problem now dealing with objects/enemies moving offscreen. Because it's possible the screen boundary is one pixel away from loading two new screens. If an object is then thrown offscreen to the right, it will either A: Interact with collision data from the left two loaded screens which could result in weird behavior, or B: Immediately be destroyed.

I want some persistence off screen, but as it is now... it's very inconsistent persistence. You could throw an object a pixel off screen, and it might vanish. Or... it might stay there while you walk like 64 pixels away from it and come back.

128x128 metatiles allows you to never have that situation come up. And of course still keeping all the benefits 32x32 metatiles provide. (512x512 pixels covered in RAM.) I'm now seriously considering changing to this, but man... there's a lot of things I'd have to update everywhere... (But I guess it also limits my level size without keeping 256x256 metatiles as well. Currently I can do any level dimensions that don't exceed 256. 64x4 screens, 128x2, 256x1 85x3 1x256... or anything less).

I could post about how I store slopes or whatever if you want, but I'm not sure it helps with point 1. Generic. The thing to realize is that with metatiles everything is easily extendible. My 16x16 metatiles are 4 arrays of top left, top right etc. Need slope type? Add an array and a fifth byte. Need more info? Add it to the fifth byte. Out of space in the fifth byte? Add a sixth.
Re: Map data formats
by on (#142450)
Kasumi wrote:
Definitely store attribute data with metatiles. (I don't think you'll have many metatiles that are identical except for their palette. Having a separate map would mean storing LOTS of redundant data whenever that's not true which is certainly the more common case.)

Yeah I agree. This was actually my plan all along and what I've done in the past. I also haven't yet found a game which didn't do this. The reason I asked about it is that I talked with somebody (an artist) who disagreed, but he probably hadn't put much thought into it, or at least the technical ramifications of it. It probably wouldn't be terribly difficult to change the code to later on support this kind of scheme, if really needed (drop the data from the metatile data, load from a separate per-screen 2bpp bitmap).

Quote:
Definitely store collision info with metatiles. (Same as above. Is storing it separately likely to save you more space than having two of the same metatile with different collision info sometimes? Unless you mean define an arbitrary slope outside the metatiles so that multiple tiles can use it. In which case, yes, do that.)

I guess the only counter-argument for that again is: do we want to save space, or to have as many graphically unique metatiles as possible? But yeah it's probably best stored in the metatile for a generic solution.

Quote:
As far as which metatile size gets this data, I'd say always the smallest one possible. You're likely to have larger (say... 32x32) metatiles that have very slightly different arrangements of smaller (say... 16x16 metatiles) metatiles. You only save space if each small metatile is used fewer than 4 times in the large ones.

Yeah. As far as space savings go, it of course depends a lot on the data. I don't really have an intuition on which way would be better from that angle, but shoving all of it in the smallest metatiles seems like an easy way to go. I guess it shouldn't be that hard to change this later on, either.

Might be interesting to throw "raw" 16x16 pixel metatile data from some games into an utility that tries different combinations of metatile sizes to see which yield the best compression, and see how much variation there is.

Quote:
Quote:
- Maximum number of metatiles? 256 is a natural limitation to use here, but how likely are artists to run out of metatiles, say at the 16x16 pixel metatile level?

The artists should be willing to meet you halfway, here. I would not go out of my way to support more than 256 of anything. (Err... but to actually answer your question, pretty likely if they don't know a lot. They're even likely to run of regular 8x8 tiles, which I see a lot a lot a lot.)

Yeah, I guess. The 8x8 tile limit is easier, because no need to make a choice there (other than whether to use MMC5 or not.) And I wouldn't want to work with an artist who wasn't willing to make him or herself aware of that limitation. :)

Quote:
I chose 32x32 metatiles as my second largest size, because you can fit 4 screens of them in a page of RAM. Having 512x512 pixels covered in RAM is super nice for a multidirectional scroller. I really, really recommend 32x32 tiles specifically, with some larger size to make it easy to seek through the level. (Screens or whatever)

Why do you have the map in RAM? Do you decompress it there, or load it dynamically, or something? What do you mean when you say you "load new screens"? Personally I was planning to keep the map data in ROM (or at least allow an option of doing so.)

Quote:
I'm now seriously considering changing to this, but man... there's a lot of things I'd have to update everywhere...

This is what I'm afraid of, so I want to make at least somewhat informed decisions. :)

Thanks for the reply, I was afraid I was going to have to do a monologue on this one. Looks like most of what you say align with what I've been thinking. And in the end, many of the differences between different methods are fairly small, so might as well just pick one and run with it.
Re: Map data formats
by on (#142454)
thefox wrote:
Metatiles of metatiles?

Always my first choice!

Quote:
I guess "screen" here is really nothing but another name for a big metatile of metatiles.

Exactly. I have metatiles all the way from 16x16 to 256x256 (going through 32x32, 64x64 and 128x128), which are the ones that are actually used in the level map. Sound crazy, but is really compact. I even considered sharing the structures across all metatiles, since they're all just arrays of 2x2 bytes no matter their size, to save even more data. That would have made the encoder insanely complex, so I never got to try this.

To decompress the map, I first locate the specific 256x256 block I'll read from, and from there I use a set of pointers that I modify in ZP. Depending on the corner of the metatile I'm reading (which is specified by bits from the coordinates), I modify the pointers to point to the specific corner, and then it's just a matter of loading an index and moving on to the next pointer, until I reach the smallest block. Sounds slow, but it's not too bad. If you had lots of RAM you could decompress larger sections progressively instead of doing it the crazy way.

Quote:
Should attribute data be stored in metatiles, or should there be a separate map for them? Same goes for collision data.

I prefer to store attributes (and I really mean all attributes, not only the palette bits that the NES calls attributes) in the smallest metatile (16x16), but the collision maps are in a separate table, and are indexed in the metatiles. I have 2 sets of collision data per metatile, in order to simulate two layers in my level maps. Triggers cause the objects to switch layers.

Quote:
256 is a natural limitation to use here, but how likely are artists to run out of metatiles, say at the 16x16 pixel metatile level?

I usually go with 256 because it's much simpler/faster to work with bytes. If you need more than that, the best option would probably be to store them in RAM and replace them progressively as the level is played.
Re: Map data formats
by on (#142456)
Quote:
Why do you have the map in RAM? Do you decompress it there, or load it dynamically, or something? What do you mean when you say you "load new screens"?

I have the map partially in RAM mainly because the screens are compressed in a way that doesn't allow random access, yeah. (Not sure if that means they're no longer considered metatiles. If so, my bad for calling them that.) I'd have to decompress for every collision if I didn't keep them in RAM somehow. They're also compressed in a way that's limited (against point 1.), so I didn't mention it.

A map in RAM is also cool if you have some destructibility. You only have to change the state of a tile once when you load it, rather than check if it's solid every single time an object needs to collide with it.

Basically when high byte of the scroll changes, I decompress the two screens that have just appeared to the 128 bytes that just moved offscreen. See GIF:
Image
To change to 128x128 metatiles, I'd need to change what updates this RAM. (And how objects are created when scrolled onto the screen.) Tile drawing and collision detection both read from this RAM to get the 32x32 metatile numbers, so the first change would fix those for free. (This is also why offscreen objects may collide with the wrong things, which wouldn't be a problem with an only ROM approach.) I mainly worry about updating the tool I use to create the maps. That's where I'd have to change things everywhere.
Quote:
Personally I was planning to keep the map data in ROM (or at least allow an option of doing so.)

There's nothing wrong with this at all. I thought there were more benefits to the map in RAM, but now that I think about it...

Quote:
Thanks for the reply, I was afraid I was going to have to do a monologue on this one.

Any time. Not like my game will ever come out anyway, may as well share the thoughts.
Re: Map data formats
by on (#142458)
You might need 'Tile Destroyed' flags, such as for collecting coins, already hit question blocks, blowing up walls, etc.
One way I've thought of doing it is to use a big map that corresponds directly to 8x8 areas of the map. It would have numbers in it, such as FF for nothing destroyable, otherwise it would have a unique number for each area containing destructible tiles, think of them as 'cell numbers'. This does not necessarily need to be in RAM, it could be in ROM.
Then you have the tiles destroyed bits, 8 bytes total per 'cell number', this is just the 64 bits of flags for whether tiles are destroyed or not.
Use a table to map a metatile to a 'destroyed' metatile.
Re: Map data formats
by on (#142461)
thefox wrote:
- Should be generic rather than limited. I don't mind losing a little bit in efficiency (in space and time) due to this. No object based formats like used in SMB1.

What's wrong in general with an object-based format?

Kasumi wrote:
A map in RAM is also cool if you have some destructibility. You only have to change the state of a tile once when you load it, rather than check if it's solid every single time an object needs to collide with it.

In a 2-way scroller like SMB2, if you're not going to have destructible objects above destructible objects, you could always use a single destruction bit per column.
Re: Map data formats
by on (#142476)
Kasumi wrote:
I have the map partially in RAM mainly because the screens are compressed in a way that doesn't allow random access, yeah. (Not sure if that means they're no longer considered metatiles. If so, my bad for calling them that.)

Understood. I think they should still be called metatiles, this method just caught me by surprise since I haven't heard of it before. The first thing that most people would probably think would be that decompressing entire screens while the game was running would be too slow, or at least make for an uneven processing load per frame.

Quote:
A map in RAM is also cool if you have some destructibility. You only have to change the state of a tile once when you load it, rather than check if it's solid every single time an object needs to collide with it.

Definitely. I hadn't even thought of the option of storing only a partial view of the map in RAM (when using a big map), although I probably won't do it because it seems complicated. :)

Quote:
Tile drawing and collision detection both read from this RAM to get the 32x32 metatile numbers, so the first change would fix those for free. (This is also why offscreen objects may collide with the wrong things, which wouldn't be a problem with an only ROM approach.)

Yeah, I had this same problem in STREEMERZ initially. I stored only the visible portion of the map in RAM, until I realized that the player should be able to interact with the walls of the upper/lower room during transitions. Since I wanted to make it behave the same way as the original, I had no option but to modify the code to load an additional couple of tile rows at the top and the bottom of the room. Of course this is not an option with a big map.

Quote:
Quote:
Thanks for the reply, I was afraid I was going to have to do a monologue on this one.

Any time. Not like my game will ever come out anyway, may as well share the thoughts.

I guess many of us here are in the same boat. :) I have actually realized I like working on engines more than I like working on games, so I'm not going to stress about getting anything complete out of this.

Dwedit wrote:
One way I've thought of doing it is to use a big map that corresponds directly to 8x8 areas of the map.

I want to go on a record to say that it can be really confusing when people talk about "8x8 areas" and don't specify what unit they use (pixels? metatiles? megatiles? inches?). I assume you meant metatiles here. This is why I used pixels all over the place in the original post in case anybody was wondering. :) Still, thanks for the thought on destroyable terrain!

tepples wrote:
thefox wrote:
- Should be generic rather than limited. I don't mind losing a little bit in efficiency (in space and time) due to this. No object based formats like used in SMB1.

What's wrong in general with an object-based format?

I didn't say anything was wrong with it. I said it's not a generic format, at least I think most people would feel limited by it.
Re: Map data formats
by on (#142494)
Dwedit wrote:
You might need 'Tile Destroyed' flags, such as for collecting coins, already hit question blocks, blowing up walls, etc.

I like to implement all of those as actual objects, not part of the level map. Whenever the camera scrolls, the background objects check for overlaps between themselves and new rows/columns, and "patch" the row/column with their own tiles. This allows breakable/removable blocks to have actual graphics behind them, as apposed to just blank space. Plus, I like that the level map is just the static part, and everything you can interact with is an object.

Objects might have permanent state bits assigned to them, so level deformation is possible, as long as the number of removable blocks isn't insanely high to the point where the CPU will have trouble dealing with so many objects or there won't be enough RAM to remember all the states.
Myask's map data formats maundering...
by on (#142498)
Disclaimer: rambling.
thefox wrote:
- Should be generic rather than limited.
Unfortunately, the preferred structure of data owes a good deal to its nature. I found reading about the MIDI format (and the superclass it owes its structure to, Interchange File Formats) to be fascinating; it seems relevant. Of course, 4 bytes for chunk-identification is likely going to be massive overkill for storing level data, but there are benefits to conforming to standards: (partial) compatibility, even if you don't understand every chunk, is feasible as the sizeof field allows you to simply discard unknowns. The non-mandatory nature of chunks suggests to me, one might have 'default' collision data for a metatile, and on occasion have a chunk added to a metatile saying "no, use this collision instead". Similarly, one might have a "this metatile relies on this memory data"; if one is not making a geomod-fanatic game, this is going to be present in relatively fewer tiles...except for the obvious case of collectibles. A simliar (possibly the same, possibly different, depending on implementation) would be one depending on saved (password/SRAM/etc.) data.

Variable-length quantities, like how MIDI does for time-deltas (summary: sign bit of a byte is "is there another byte to this number") are a simple way of providing extreme extensibility (and, if incautious, buffer overflows) to fields.

The problem with this is that often, map-proximate tiles are going to be source-proximate, so you'll have a lot of data redundancy if you do this on a per-tile basis. One could instead specify the first (meta)tile as absolute, and for other (meta)tiles within the (meta)tile, only specify the relative address or lower byte(s), in similar fashion, using VLQs for the subsequent ones.

On the crazy side, there will never be a time when you need more than 18 bytes to select a graphical 8px*8px tile on the NES. (16 bytes for the tile, 2 bytes for "ridiculous-mapper" per-8x1-sliver attribute).

Attributes should probably be per-32*32px metatile under normal circumstances; this makes it easy to copy into the PPU attribute tables.

Collision being stored separately to graphics, and at which level? There are two obvious NES-like cases where you want them disparate (illusionary/invisible walls/structures) as well as for "foreground".

A truly-universal object would just be a function pointer "run this when this scrolls in", leaving further determination in said code. Obvious extensions are a "dead" or status flag to say when (/not) to run it again. One could store palette changes in this fashion, with a batch at the start of the level to initialize them.

If you are doing a "net-of-screens(~256*256px(240?) metatiles)" approach, then one thought is that one might wish to is that one might wish to be able to change the direction of the coordinate system of said 'screen's, so as to more easily be able to extend the level forward. The one UR-scrolling level in SMB3 would have +y be up rather than down, in this thought...but you're likely to not have any need for this sort of affair if you are creating your own tools to produce the data.

Sources: the MIDI Technical Fanatic's Brainwashing Center (mirror)
Re: Myask's map data formats maundering...
by on (#142513)
Myask wrote:
Disclaimer: rambling.

Now, something like this is too generic for my purposes. :) And it would destroy performance.
Re: Myask's map data formats maundering...
by on (#142515)
Myask wrote:
Attributes should probably be per-32*32px metatile under normal circumstances; this makes it easy to copy into the PPU attribute tables.

Unless you scroll vertically, in which case blocks in every other screen are misaligned to the attribute grid, and will require you to do some bit shuffling in order to form the attribute bytes. Another factor is that if you're using 8 or 4-way scrolling without extra name table RAM on the cartridge, one of the axes will not have 32 continuous pixels you can modify at once without causing glitches on the opposite side of the screen, so you will have to break up the bits anyway.
Re: Map data formats
by on (#142521)
True...unless one is using nametable-size "screens" so the cuts on the half-metatiles are already in-place.
Re: Map data formats
by on (#142522)
Myask wrote:
unless one is using nametable-size "screens" so the cuts on the half-metatiles are already in-place.

True for the misalignment, but the 4/8-way scrolling and the lack of space to put the scrolling seam still applies.

Still, I kinda like the idea of assigning attributes to the 32x32-pixel blocks, even if some bit shifting is necessary.
Re: Map data formats
by on (#142580)
Eh, it probably still helps with ROM space usage, which is probably what matters most.
Re: Map data formats
by on (#143657)
I settled on 256x256px metatiles of 32x32px metatiles of 16x16px metatiles for now.

I wrote a little utility to convert flat array maps into that format. I was a bit sad to notice that the metatiles from the first level of Batman couldn't fit into the 256 32x32px metatile limit imposed by the format. I think the game originally used 32x16 metatiles.

Anyway, I've been thinking of a 6502 implementation of a multidirectional map scroller now, and wanted to ask if anybody has any useful tricks when it comes to that before starting on it. I have implemented one multidirectional scrolling engine in the past, but I want to do this one from scratch. I've already written a prototype of such scroller in Lua, but it uses a very naive way for creating the tile updates.

I feel like the hardest part is figuring out how to build the tile update buffers as efficiently as possible. So, here are the basic problems that need to be taken into account:

- Nametable crossing (both vertical and horizontal). When creating PPU updates, the update needs to be split into two pieces whenever the update would cross a nametable boundary. There should be at most one nametable crossing, since it wouldn't make sense to have row/column updates longer than roughly one nametable width/height. In the typical case there's exactly one crossing.
- Screen crossing. Again, there should be at most one of these per horizontal/vertical update. Not necessarily aligned with nametable crossings.
- Different sub-metatile offsets (and metatile boundary crossing). E.g. we might start a vertical update from the left or the right side of a 32x32px metatile (and likewise for the 16x16px metatile within it). Might have a different vertical starting offset, too.
- Attribute updates. Need a "cache" in CPU memory of the current attribute contents to be able to construct the updates non-destructively. A cache of roughly 64 bytes should be enough.
- Different mirroring modes impose different limitations.

I was thinking it might make sense to figure out all of the different scenarios (different sub-metatile starting offsets, etc) that can happen, and write (probably with macros) separate routines for handling each one of them.

Any tips or tricks?
Re: Map data formats
by on (#143660)
thefox wrote:
Anyway, I've been thinking of a 6502 implementation of a multidirectional map scroller now, and wanted to ask if anybody has any useful tricks when it comes to that before starting on it.

Not exactly a trick, more like an advice: Don't bother with vertical alignment between name tables and 256x256-pixel metatiles. Converting between map space and NT space will probably require an awkward and time-consuming division by 15. It's much simpler to just have 2 CameraY coordinates, one relative to the level (which you use to read data from the map) and another one relative to the name tables (which you use for scrolling and drawing). Just update both by the same amount every time and have the NT one wrap from 239->0 and vice-versa.

Quote:
- Nametable crossing (both vertical and horizontal). When creating PPU updates, the update needs to be split into two pieces whenever the update would cross a nametable boundary. There should be at most one nametable crossing, since it wouldn't make sense to have row/column updates longer than roughly one nametable width/height. In the typical case there's exactly one crossing.

I accounted for this in the code that draws the tiles to VRAM. The buffers are always 68 (rows) or 60 (columns) bytes, but the code that copied them to VRAM uses counters and/or pointers to break those in 2 parts (actually 4, since each metatile is 2x2 tiles).

Another advice is: don't bother with partial attribute table updates. The logic to handle name table crossing will take as much time as simply updating an entire row or column, including the parts that are off screen.

Quote:
- Screen crossing. Again, there should be at most one of these per horizontal/vertical update. Not necessarily aligned with nametable crossings.

I handle that by always preparing 2 256x256-pixel metatiles for reading. When I start decoding data from the level map, I get the index of the block where the row/column starts and the one after it. For columns, the second block isn't always used.
Quote:
- Different sub-metatile offsets (and metatile boundary crossing). E.g. we might start a vertical update from the left or the right side of a 32x32px metatile (and likewise for the 16x16px metatile within it). Might have a different vertical starting offset, too.

I use pointers to indicate which parts of the metatile I'll be reading. Each metatile has 4 children, but I only need to read 2, and based on the row/column coordinate I know which 2 those are, so I build a set of pointers before reading the data. This might not work so well in you case, since there are many 32x32-pixel metatiles inside the 256x256 ones, not only 4.

Quote:
- Attribute updates. Need a "cache" in CPU memory of the current attribute contents to be able to construct the updates non-destructively. A cache of roughly 64 bytes should be enough.

I have all 128 bytes chached just to make them easier to access (i.e. the addresses are always in sync with the attribute tables), but a portion the size of the screen should indeed be enough. In fact, if you don't plan on modifying tiles in the middle of the screen, you could probably get away with keeping track of the edges of the screen only.

Quote:
I was thinking it might make sense to figure out all of the different scenarios (different sub-metatile starting offsets, etc) that can happen, and write (probably with macros) separate routines for handling each one of them.

I considered doing this too, but routines for columns or rows starting on each of the 256 metatiles of a screen would be too insane to do, and combining that with other solutions (like a pointer system) would probably not result in such an improvement.

A solution I have used at some point is to always decode rows and columns that are 32 metatiles wide/tall from the level map using the fastest possible unrolled code, and then extract from there the tiles that are actually necessary. Sounds like a waste of resources, but sometimes it's faster to just do the unrestricted full process (which can usually be optimized) and discard some of the data than worrying about boundaries, counters and such during the process.

You could maybe write specific routines for each of the 16 rows and 16 columns, that always read 32 metatiles, and have the VRAM update code only use the part that will be visible next frame.
Re: Map data formats
by on (#143880)
tokumaru wrote:
Not exactly a trick, more like an advice: Don't bother with vertical alignment between name tables and 256x256-pixel metatiles. Converting between map space and NT space will probably require an awkward and time-consuming division by 15. It's much simpler to just have 2 CameraY coordinates, one relative to the level (which you use to read data from the map) and another one relative to the name tables (which you use for scrolling and drawing). Just update both by the same amount every time and have the NT one wrap from 239->0 and vice-versa.

Yeah, I was planning to do this. In my last scroll engine I had actually a separate set of coordinates for each edge of the view area. But I'm not sure if that was a good idea, undecided at this point about whether to do it again. Also not sure whether to do even horizontal alignment. I think it would be kind of nice if there was no requirement about the horizontal map-nametable alignment (except obviously attribute tile alignment requirement, and probably 32x32px metatile alignment would be good to have also).

Quote:
I accounted for this in the code that draws the tiles to VRAM. The buffers are always 68 (rows) or 60 (columns) bytes, but the code that copied them to VRAM uses counters and/or pointers to break those in 2 parts (actually 4, since each metatile is 2x2 tiles).

Interesting. I hadn't thought about doing it on the VRAM copy side.

Quote:
Another advice is: don't bother with partial attribute table updates. The logic to handle name table crossing will take as much time as simply updating an entire row or column, including the parts that are off screen.

Thanks. I believe I did partial updates in my previous scrolling engine. This time I plan to profile the code before and after any changes.

Quote:
Quote:
- Screen crossing

I handle that by always preparing 2 256x256-pixel metatiles for reading. When I start decoding data from the level map, I get the index of the block where the row/column starts and the one after it. For columns, the second block isn't always used.

Ah, that's also a good point. Can easily be done since we always know there's at most two.

Quote:
Quote:
- Attribute updates. Need a "cache" in CPU memory of the current attribute contents to be able to construct the updates non-destructively. A cache of roughly 64 bytes should be enough.

I have all 128 bytes chached just to make them easier to access (i.e. the addresses are always in sync with the attribute tables), but a portion the size of the screen should indeed be enough. In fact, if you don't plan on modifying tiles in the middle of the screen, you could probably get away with keeping track of the edges of the screen only.

Good point about modifying stuff in the middle of the screen. I do want to have support for that, because of the aforementioned genericity goal.

Quote:
Quote:
I was thinking it might make sense to figure out all of the different scenarios (different sub-metatile starting offsets, etc) that can happen, and write (probably with macros) separate routines for handling each one of them.

I considered doing this too, but routines for columns or rows starting on each of the 256 metatiles of a screen would be too insane to do, and combining that with other solutions (like a pointer system) would probably not result in such an improvement.

I wasn't actually planning to have a full set of routines for all the options, but figure out a fair set of "similar" ones. But yeah, not really sure yet whether I'll go with this one.

Quote:
A solution I have used at some point is to always decode rows and columns that are 32 metatiles wide/tall from the level map using the fastest possible unrolled code, and then extract from there the tiles that are actually necessary. Sounds like a waste of resources, but sometimes it's faster to just do the unrestricted full process (which can usually be optimized) and discard some of the data than worrying about boundaries, counters and such during the process.

You could maybe write specific routines for each of the 16 rows and 16 columns, that always read 32 metatiles, and have the VRAM update code only use the part that will be visible next frame.

You mean 32 metatiles 16x16px that are aligned to the 256x256px metatiles? That's an interesting idea, too. Hadn't thought about that one either, thanks.
Re: Map data formats
by on (#143882)
thefox wrote:
Interesting. I hadn't thought about doing it on the VRAM copy side.

Well, my pointers and indices were calculated during draw time, and the VRAM routine just loaded up the indices and jumped to the locations indicated by the pointers. I had separate routines for each kind of VRAM update though, but if you have something more generic already set up (i.e. "copy NN bytes from XXXX to YYYY") it would probably make more sense to split rows and columns into multiple copy commands beforehand.

Quote:
I believe I did partial updates in my previous scrolling engine. This time I plan to profile the code before and after any changes.

Profiling would be a good idea. In my own design, the same logic I used to break name table updates in half was saving me very little time when applied to attributes to be worth the trouble. I gave up on it mostly because my VBlank time was split into "VRAM update slots", and there were only 2 slots per frame. Taking the DMA transfer, scroll setting and other minor housekeeping tasks into account, there were 840 or so cycles left for each of the 2 update routines. That was enough for updating a row/column of tiles along with a full row/column of attributes, so there really was no reason to insist on the split, because the little time saved wouldn't have been used for anything.

Again, if you use a more generic VRAM update system, it might be worth it to reduce the byte count a bit.

Quote:
Good point about modifying stuff in the middle of the screen. I do want to have support for that, because of the aforementioned genericity goal.

Yeah, that's a serious requirement for me. I want to be able to destroy/move background objects and have actual content behind them, not only color 0.

Now that I think of it, I'm not sure if only 64 bytes would be enough for keeping track of attributes, since the area covered by the camera can be slightly wider than 256 pixels depending on the alignment with the metatiles. Maybe if you force columns to be recalculated when switching scrolling directions, but I'm not sure. It's something to consider.

Quote:
You mean 32 metatiles 16x16px that are aligned to the 256x256px metatiles? That's an interesting idea, too.

Yeah, but I don't fully decode the 16x16s at this time, I just get their indices into a 32-byte array, in which I scan the range I'll actually need and then decode the tile indices and attributes in preparation for the VRAM updates.

I didn't do any serious optimization in the reading of the 16x16s in my engine, but since you suggested some kind of unrolling that seemed like a nice place to do it.

Quote:
Hadn't thought about that one either, thanks.

I'm glad to have given you something to think about. =)
Re: Map data formats
by on (#143910)
tokumaru wrote:
Now that I think of it, I'm not sure if only 64 bytes would be enough for keeping track of attributes, since the area covered by the camera can be slightly wider than 256 pixels depending on the alignment with the metatiles. Maybe if you force columns to be recalculated when switching scrolling directions, but I'm not sure. It's something to consider.

Yeah, that's why I said "roughly 64" originally. I guess 9x9 = 81 bytes should be enough to cover all scenarios. But like you said, addressing the cache becomes trickier, probably need to keep a separate set of counters for the position(s) inside the attribute cache as well. For one-screen mirroring 64 bytes should be enough.
Re: Map data formats
by on (#143946)
All block metadata is in a block metadata table. There you have collission type as in slope type, is the airspace of the block air or water, is the whole block a ladder, is the object special (pipe, flagpole, etc), can you hit it from the bottom and get something out of it, etc.
This is how I'd make a Mario game
Code:
0x00-0x03 = Associated tiles
0x04 = Collission settings
0x04 0B---xxxxx= Collission type / Slope shape
0x04 0B-xx----- = On solid part collission (0: Obstacle, 1: Ladder, 2: Top-collission only obstacle, 3: Unused)
0x04 0Bx------- = On empty part collission (0: Air, 1: Water)
0x05 = Collission behavior
0x05 0B-------x = On top collission (0: Regular, 1: Ice/low friction)
0x05 0B---abcd- = Get hurt on (a=1: top, b=1: left, c=1: right, d=1: bottom)
0x05 0B--x----- = Breakable block from underneath
0x05 0B-x------ = Pickable object
0x05 0Bx------- = Bounce down when bumped from underneath
0x06 = Block type
0x06 0B----xxxx = How does the block work (0: Regular, 1: Collectable, 2: Has something inside, 3: Unused, 4: 2-block pipe entrance up, 5: 2-block pipe entrance left, 6: 2-block pipe entrance right, 7: 2-block pipe entrance down, etc)
0x06 0B-1xx---- = This block is a segment of a 2x2 block (Giant World) (0: Upleft, 1: Upright, 2: Downleft, 3: Downright)
0x07 = Extra data (if 0x05=0B-1------ then it's the entity ID of the object that will be held (like Blue Block from SMB3). Else if 0x06=0B----0001 then it defines what you get when you collect. Else if 0x06=0B----0010 then it's what gets ejected from the block. Else if 0x06=0B----01-- then you select which pointer on the map will send the player to another location


All blocks are 16x16 pixels and are placed on a page and each page is 16x16 blocks. The map itself can have pointers to the beginnings of these pages.
Code:
0x00 = Number of pages
0x01+Number of pages*2 (24-bit value) = Pointer to which place from which PRG-ROM bank
NEXT SEGMENT:
0x00 = Number of entities (enemies, pointers, etc.)
to be done


So that's how you can have a map.

The blocks are loaded into the WRAM from where they are read into the game and written when breaking or changing some of them.
Re: Map data formats
by on (#144323)
8bitMicroGuy wrote:
...

What metadata to store for blocks is not really relevant for this discussion. The 16x16px metatile format you propose is simple, but also uses quite a lot of space. Also I forgot to mention it in the original post I think, but I don't want the solution to depend on WRAM in any way.
Re: Map data formats
by on (#144340)
thefox wrote:
- Should not depend on extra cartridge RAM (but should be able to work with maps decompressed to WRAM).


thefox wrote:
8bitMicroGuy wrote:
...

Also I forgot to mention it in the original post I think, but I don't want the solution to depend on WRAM in any way.


Huh? Did I miss something in-between the posts that I didn't read?
Re: Map data formats
by on (#144341)
Roth wrote:
Huh? Did I miss something in-between the posts that I didn't read?

I edited that into the first post after I noticed it. There's an "EDIT" note at the bottom of the first message. :)
Re: Map data formats
by on (#144355)
thefox wrote:
Also I forgot to mention it in the original post I think, but I don't want the solution to depend on WRAM in any way.

That's usually my approach too. At some point I noticed you didn't say anything about this, but once we started discussing the decoding process it started looking like you didn't plan on using WRAM.

WRAM is really nice for when you need to keep track of a lot of game state, but more often than not, levels in WRAM are not as modifiable as being in RAM could allow them to be. In these cases, the WRAM ends up being nothing more than a facilitator, making the scrolling engine (and possibly the collision detection) more straightforward.

I don't think WRAM is evil and should be avoided at all costs, but sometimes I feel like people choose to use it without giving much though to what could be accomplished with the built-in 2KB of RAM. It's understandable, a lot of people (most notably commercial programmers from back in the day) are entirely focused on shipping the game, so anything that makes the programming easier is game. I personally enjoy the problem-solving steps of game development, thinking up of clever ways to do things. It's part of the fun in this hobby.
Re: Map data formats
by on (#144435)
Alright. NES without WRAM, but only its own RAM is 2kB.
Surely you'll have player stats and other things in ram so that's 2048-256(stack)-256(zero page for player and enemy data)=1536 bytes
So if every page is 16x16 blocks that are 16x16 pixels, that's 256 blocks. If every block is one byte (which means no metadata will be in blocks) and you could walk around the game in all ways without having it forget the stage (like in SMB1), you would have maximum 6 pages of level. I think that's too little for a level.
If you'd have a level in which all data is forgotten and everything is running on 2 pages like SMB1, then you'd have maximum 3 bytes per block.
If you'd have one page only, you'd have maximum of 6 bytes per block.
If you'd have one and half a page (which would be hard to implement), you'd have maximum of 4 bytes per block.
Personally, I would go for 3 bytes per block and 2 pages. That would be good for some fancy SMB1 remake with lots of blocks with lots of data.

Now, I should have modified the size of pages because not all blocks would fit the screen or even the TV; scanline cutoff. If every page is 16x13 (2 blocks are invisible from the status bar like in SMB and nobody actually cares for the block on the bottom), then every page is 208 bytes.
Maximum pages on a full level = 7
Maximum bytes per block on a 2 page level buffer = 3
Maximum bytes per block on a 1 page level buffer = 7
Maximum bytes per block on a 1.5 page level buffer = 4.9 ooof almost 5

As I said, I'd go for a 16x16 level with 3 bytes per block and 2 pages.
Block structure would be like this
Code:
Regular blocks:
0b XXXXXXXX XXXXYYCC CCCCCCCC
X's are block art
Y's are the color pattern
C's are the object's collission data: slope shape, obstacle/ladder/top-collission, deadly on touch, air/water; like explained in my previous post
Special blocks:
0b XXXXYYMM MMMMMMCC CCCCCCCC
X's are block art
Y's are block color pattern
C's are the object's collission data: same as above.
M's are the object metadata (Pipe target, what it contains, etc)
Re: Map data formats
by on (#144439)
8bitMicroGuy wrote:
2048-256(stack)-256(zero page for player and enemy data)=1536 bytes

Hah, you're dreaming if you think you can get away with only 512 bytes of game state just so you can have 1536 bytes for the level.

In my Sonic engine (the latest version at least), most of the RAM goes to active objects, and big parts are used for scrolling, music, persistent game state, and many other features. I don't have the RAM to hold a single screen, all level data is directly loaded from ROM.

I've seen a few designs that keep 2 screens in RAM, and that sounds reasonable. Another aproach is to have larger metatiles in RAM, such as 32x32 pixels, so that 256 bytes can hold 4 screens, enough for multi-way scrolling.

Whatever the case, you should not be using the majority of the built-in RAM for levels, sacrificing other features, just because you're to lazy to come up with a more suitable compression format. Better go with WRAM in this case.
Re: Map data formats
by on (#144693)
I'll back up Tokumaru here: it's entirely possible to implement a multi-way scrolling engine using minimal ram. However, to do so you need to spend more time thinking about how you'll lay out your map data structures in ROM. Thus the first page of this thread, entirely dedicated to how map data should be laid out. :)

A scrolling engine I've implemented uses 16 bytes for camera position, 5 bytes for scrolling position, 9 bytes for the map data, and 16 bytes that tracks the currently loaded tileset. I also keep 96 bytes in zp for the vblank buffer. Aside from that, all my ram is free for game state and stack.

One idea which I really like is the multiple sizes of metatiles! I hadn't thought of that. Instead of collections of metatiles, I decided to implement a system of multiple-data-indirection, so a map is made up of superchunks, which is made up of chunks, which is made up of metatiles, which is finally made up of graphic tiles and attributes.

Just for comparison's sake, here is how I lay out my map data:
A map is a square of SuperChunks. The size of the map can be from 8x8 to 64x64 superchunks.
A SuperChunk is 2x2 Chunks.
Each Chunk is 8x8 MetaTiles.
Each MetaTile is 2x2 8x8 Graphic Tiles + Attribute (block, etc.).

Tile gfx banks (up to 8 8-kb banks)
2x 256 x 16 byte tiles each

Chunk banks (up to 8 8-kb banks)
128 x 64 byte chunks each

Code:
MAPS
Each map is comprised of a Map Header, Superchunk Pointer Set, and Superchunk Data.

MAP HEADER
Each map is described by a 2b header value. These headers are located in the core ROM bank.

1b bank/index - location of main map bank
    76543210
    BBBBBiii
    B = bank where Superchunk Pointer Set is located (0-31)
    i = index of SuperChunk location in specified bank (0-7)
1b tileset used by this map and size flag
    76543210
    sstttttt
    s = size of map
        00 = 8x8    (2048p square map, pointer set is 64x2 = 128b)
        01 = 16x16  (4096p square map, pointer set is 256x2 = 512b)
        10 = 32x32  (8192p square map, pointer set is 1024x2 = 2kb)
        11 = 64x64  (16384p square map, pointer set is 4096x2 = 8kb)
    t = tileset used by this map.
Code:
SUPERCHUNK POINTER SET
The Superchunk Pointer Set is 2kb, and is located in bank B (0-31), at
[$8000 + $00iii000 00000000], where B and i are taken from the Map header.

The Superchunk Pointer Set designates a set of 8x8 to 64x64 superchunks. The Superchunk
Pointers are interleaved by halves. For a 32x32 superchunk map, the pointers are laid out
as such:

    $0000 Map Lo byte SuperChunk pointer (1024)
    $0400 Map Hi byte SuperChunk pointer (1024)

Each pointer is 2 bytes, and is comprised of:
    76543210 76543210
    bbbppppp ppPPPPPP
        b = bank offset (0-7) added to the bank value B from the map header.
        pP = pointer, pointing to $8000 + %00PPPPPP ppppppp0
        Note that bank index can be incremented based on map index.
       
    If a pointer is $0000, then there is no data for this superchunk. Otherwise, the
    pointer points to memory location: [$8000 + %00PPPPPP ppppppp0] in bank [B + b].
Code:
SUPERCHUNK DATA SET
Each SuperChunk data set is comprised of 1b flags, 5b Chunk indexes, and any
combination of the following:
    * Alternate SuperChunk data
    * Actor data
    * Egg data
   
1b Flags
    76543210
    .....EAL
    L = 1 : has aLternate superchunk data
    A = 1 : has Actor data
    E = 1 : has Eggs data

5b Chunk Indexes
    4b Chunks in this SuperChunk
    1b Hi bits for Chunks
        76543210
        BRblURul
(Omitting alternate superchunk data, actor data, and egg (scripting) data for brevity. Ha! Brevity...)
Code:
TileSet banks (4 TileSets per bank, 800 left over)
* Updated 01/02/13
   Tileset header: 2b pointers.
   
   Each tileset is 1848b, organized as follows:
   255 MetaTile bitfields
   1b pal index zero
   255 MetaTile attributes
   1b palette 0
   255 MetaTile graphics UL
   1b palette 1
   255 MetaTile graphics UR
   1b palette 2
   255 MetaTile graphics LL
   1b palette 3
   255 MetaTile graphics LR
   byte tilecount, always 208
   tilecount b tiles low bytes.
   tilecount / 2 b tiles hi byte
      -   (lo nibble is for $0 index, hi nibble is for $1 index)
      -   Tile graphic index is a 12 bit number, 0-4095
   200 free bytes follow each tileset.

The code in motion is attached (attribute and sprites aren't implemented, but scrolling is - and it looks pretty darn good if I do say so myself :)).
Re: Map data formats
by on (#144701)
I've released the source code for the above multi-directional scroller (and the editor used to create the data for the same) on my github account under the MIT license. I hope it is useful to someone!
https://github.com/ZaneDubya/GalezieNES
Re: Map data formats
by on (#144764)
Can't open because the mapper isn't supported. Which emulator can run this?
tokumaru wrote:
Whatever the case, you should not be using the majority of the built-in RAM for levels, sacrificing other features, just because you're to lazy to come up with a more suitable compression format. Better go with WRAM in this case.

RAM compression!? You can't compress the RAM! If you can, you'd have to can decompress which would need more RAM. Also, my games are kind of SMB3 and Minecraft where blocks can be broken, opened, etc.

Do you think that loading level data from ROM only while treating the ? blocks as active objects would be a better idea? Then I'd have more space + ? blocks. Is it possible?
Re: Map data formats
by on (#144765)
Mapper 28 is tepples's multi-discrete mapper.
Re: Map data formats
by on (#144766)
8bitMicroGuy wrote:
RAM compression!?

I didn't mean compression in RAM (although that's also possible), I meant a compression scheme in ROM that can be decompressed on the fly.

Quote:
You can't compress the RAM! If you can, you'd have to can decompress which would need more RAM.

You most certainly can! You're thinking of compression schemes like RLE or LZ, which have to be decompressed in chunks before you can use the data, but there are other schemes that allow for random access, so you can decompress on the fly, without having to decode big blocks of data to RAM.

The Sonic games on the MD/Genesis are a good example of this: Levels are stored in the ROM using traditional LZ and Huffman schemes, but once decompressed to RAM this data is not a flat level, it's actually a map of 256x256-pixel chunks (in Sonic 1 and CD - 2, 3 and Knuckles use 128x128-pixel chunks), which are composed of 16x16-pixel metatiles. This means that levels are still compressed, in RAM, but this specific compression format is easily accessible in real-time.

Quote:
Also, my games are kind of SMB3 and Minecraft where blocks can be broken, opened, etc.

Levels can still be changed to a certain degree even when they are stored in ROM. In my engine, modifiable blocks are stored as objects, and they claim a few bytes of RAM to represent the states of each block in the object. For example, a breakable wall that's 2x8 blocks. The object has a pointer that indicates the first of the 2 bytes (16 bits) of RAM it needs to represent the state of its 16 blocks. I dedicate 128 bytes for this purpose, meaning I can have up to 1024 modifiable blocks in each level (or level section, if I prevent backtracking from a certain point), even though my levels are in ROM.

Quote:
Do you think that loading level data from ROM only while treating the ? blocks as active objects would be a better idea? Then I'd have more space + ? blocks. Is it possible?

That's how I go about it. Nearly everything that's not terrain in my engine is an active object, which can point to RAM locations where their state can be saved. This is also interesting because I can reuse screens and use objects to make them slightly different, by adding walls, platforms, and such.
Re: Map data formats
by on (#144769)
So if I'd be making a quaddirectional Mario game without WRAM, but with ability for large levels with remembering ? blocks, all the unbreakable blocks, terrain and scenery would be in ROM while the ? blocks and enemies would be in RAM. Right?
Re: Map data formats
by on (#144775)
8bitMicroGuy wrote:
So if I'd be making...

If you'd be making it, these decisions would be up to you, but I can tell you how I'd do it... :wink:

Quote:
...a quaddirectional Mario game without WRAM, but with ability for large levels with remembering ? blocks, all the unbreakable blocks, terrain and scenery would be in ROM while the ? blocks and enemies would be in RAM. Right?

Yeah, that's how I'd do it. Objects normally have bits in RAM indicating their existence anyway, and it would be the same for ? blocks. The only downside I can foresee is that enemies and other objects might need to collide with these special objects too (e.g. Goombas walking over ? blocks), so you'd have to do some extra collision detection.

The above is for reading everything directly from the ROM, but if you take the approach of maintaining 2 or so screens in RAM, which is also very common, you could just modify this temporary copy of the level based on the object's existence bit, and do collisions normally.
Re: Map data formats
by on (#144912)
Is collission detection in one frame for all of these objects possible?
How would the gameplay look like if I would skip every one of two frames because of the collissions?

I think the best method would be to compare everything with everything and then have a collission table of who collided with who.
In C, that would be bool collissions[MAX_OBJS][MAX_OBJS];
In C++, that would be vector<vector<bool>> collissions;
Re: Map data formats
by on (#144916)
8bitMicroGuy wrote:
Is collission detection in one frame for all of these objects possible?

I don't know... do you plan on having a lot of objects active at once?

In my case, clusters of interactive blocks are treated as a single object, with bits specifying the existence of the individual blocks. This means that when objects aren't close to these clusters, a single collision check is enough to determine that the object isn't touching any of the blocks, so this doesn't become particularly CPU intensive.

Most of the time I try to keep enemies away from interactive blocks though, so I don't have to bother with that. For example, Bridges are treated as objects, and an enemy walking towards it will not be able to see the bridge or cross it, so it will simply bounce back and start walking the other way, since it found a ledge. I don't think anyone would find that particularly strange. Enemies simply don't do certain things, and that's normal.

Quote:
How would the gameplay look like if I would skip every one of two frames because of the collissions?

You mean skipping all updates or just collisions? Skipping everything would drop the frame rate down to 30 or 20fps, and that wouldn't be pleasant for people used to gaming at 60fps. If you mean collisions, as long as the objects don't move very fast, it should be OK to only test half the objects every other frame.

Quote:
I think the best method would be to compare everything with everything and then have a collission table of who collided with who.

Ideally yes, but everything against everything scales up fast and CPU time is precious. I'm sure that every game has objects that are not supposed to collide (such as enemies vs. items, or enemies vs. enemy projectiles), so it would be a waste of CPU time to test everything. The approach I usually suggest is creating lists for the different kinds of objects (e.g. a list of enemies, a list of items, a list of player bullets, a list of enemy bullets, etc.), and when processing each object, testing only for collisions against the types of objects that affect the object being processed.
Re: Map data formats
by on (#144969)
What if a Goomba and a Koopa both have their colission codes for colission between each other and I'm at the maximum of the allowed colission checks? Or how about a fireball? Mario fires a fireball and it is overlapping an enemy, but the code of the enemy coliding with Mario gets run before that? I think I'm going for the frame skipping option. It's more stable and just.
Re: Map data formats
by on (#145012)
8bitMicroGuy wrote:
What if a Goomba and a Koopa both have their colission codes for colission between each other and I'm at the maximum of the allowed colission checks?

What do you mean "maximum allowed collision checks"? I don't think such a thing exists... if you have too many objects and the engine ends up doing too many collision checks the game will lag (i.e. take longer than a frame to finish the frame calculations), that's all...

Quote:
Or how about a fireball? Mario fires a fireball and it is overlapping an enemy, but the code of the enemy coliding with Mario gets run before that?

I don't see a problem with Mario taking damage and the enemy dying at the same time... is that the issue?

Quote:
I think I'm going for the frame skipping option. It's more stable and just.

I don't see how that solves anything (not that I saw a problem to begin with)... care to give an example?
Re: Map data formats
by on (#145181)
If I have special objects all over the map and enemies and Mario on the same screen, I'll surely have to frame skip in order to check all collissions and do all code. You just reminded me of SMB3 where on too many enemies, the game lags, but the music plays seamlessly. Now, a laggy game won't be nice so a 30fps game would be better. It would be something like Game Maker (where games run by default at 30fps).
Re: Map data formats
by on (#146637)
tokumaru wrote:
I don't see a problem with Mario taking damage and the enemy dying at the same time...


Funny story: the first time I got to the end of Megaman X, both the final boss and I had 1 sliver of health left. We both hit each other at the exact same frame, and the game froze. I had to replay about an hour's worth of stages to get back to that point.

So, you just need to program accordingly so that this scenario doesn't break the engine.
Re: Map data formats
by on (#146728)
Celius wrote:
tokumaru wrote:
I don't see a problem with Mario taking damage and the enemy dying at the same time...


Funny story: the first time I got to the end of Megaman X, both the final boss and I had 1 sliver of health left. We both hit each other at the exact same frame, and the game froze. I had to replay about an hour's worth of stages to get back to that point.

So, you just need to program accordingly so that this scenario doesn't break the engine.

LOOOOOL XDDDD
Re: Map data formats
by on (#146731)
Boss: "fuck you, I'm taking you with me!" *crashes the game*

OK OK back on the original discussion. That must have been rage worthy though =P