What kind of tricks are involved in animating background tiles? Does it require certain mappers?
shawnleblanc wrote:
What kind of tricks are involved in animating background tiles? Does it require certain mappers?
A mapper is not necessary, but one that has fine CHR-ROM bankswitching (in 1KB or 2KB chunks) helps, because you can animate a large number of tiles at one at nearly zero CPU cost.
If you are not using such a mapper, the second best option is CHR-RAM. During VBlank you can modify a number of tiles in the pattern tables, but it takes time because you have to manually copy every byte. Considering that most of the time there are other things to do during VBlank, realistically you'll be able to update 4~8 tiles per frame, unless you use forced blanking.
The worst option would be to keep all the animation frames in the pattern tables at all times (occupying space that could be used for other things) and modify the name tables instead. This is not very practical because it's hard to keep track of what needs to change, and because the amount of data to change can vary a lot (some sections of the level might need just a couple of tiles updated, while others might need hundreds of tiles).
EDIT: There's another type of animation that relies on palette changes. If you use only 2 colors you can have 2 frames of animation simply by modifying the palette. I believe Mega Man 2 did this for some of its backgrounds.
Anyway, if want to implement a particular effect, just tell us what mapper you are using (or which ones you'd be willing to use) and what kind of effect you're shooting for and we'll be able to tell you the best way to achieve it.
I think the most pain-free way is to go MMC3. From what I hear it maks it dead simple, which makes sense. Have 1/4 of tiles just be animated reserved. And even unanimated tiles don't have to be be changed with different animation cycles. Heck, if I had an option with today with making a game, I'm sure a mapper with 32KB CHR-RAM would be doable and one of the best options. You get mapping and RAM, win win.
3gengames wrote:
I'm sure a mapper with 32KB CHR-RAM would be doable and one of the best options. You get mapping and RAM, win win.
This idea comes up fairly frequently when we discuss the possibility of new mappers. This is indeed a win-win situation (if the memory is switchable in small enough chunks, that is), because you can use any of the solutions I mentioned above.
Yep, MMC3 with 4 banks of CHR-RAM for me is probably the best thing that could ever be made, but so few agree.
If it weren't for the incompatibility between the scanline counter and 8x16 sprites using tiles from both pattern tables I'd totally agree with you. That limitation is a deal breaker for me.
If you use TGROM (MMC3 with CHR RAM, used by Mega Man 4 and 6 and something far more obscure), there's enough space in the right ($1000-$1FFF) pattern table to store both the current and next tile data for all 64 sprites. On frames when you don't load a new row of nametable, you can replace five different 8x16 tiles with moderately unrolled code and no forced blanking. Can you show me what kind of reuse you would want to do, how the pattern tables would be laid out with sharing? I might be able to help you reallocate the right pattern table to eliminate the need for sharing.
Let me explain why sharing tiles is so important to me (didn't I already?): I have objects (items) that can be rendered as sprites or background. Ideally they'd be always rendered as sprites, but because of the low limit of 8 per scanline I really need to use the background if I want to have a number of them lined up horizontally.
So far so good. I could even duplicate the tiles and it wouldn't be such a big loss, but here's the catch: the objects are animated. This is a problem no matter if I use CHR-RAM or ROM. If I use CHR-RAM I have to update twice as many tiles (impossible because of the little time available), or lose the sync between the sprite objects and the background ones (not visually pleasant). If I use CHR-ROM I'd have to waste a LOT of space with repeated tiles because the same animation would have to be made with 1KB chunks and 2KB chunks.
The other solution would be to animate just the background tiles, and keep all sprite frames mapped in at all times so that any animation frame could be displayed, but that would steal a lot of space at the sprite side.
See the problem?
tokumaru wrote:
If it weren't for the incompatibility between the scanline counter and 8x16 sprites using tiles from both pattern tables I'd totally agree with you. That limitation is a deal breaker for me.
With new mappers though, couldn't you make one that has a bit that is setable for 8x16 sprites and just half the A13 or whatever lines clocks? Would that be too hard?
tokumaru: Thank you for your explanation. It looks like you're running out of time pushing the same tiles to both pattern tables. But as I understand it, CHR A10-A12 goes through the MMC3 even with CHR RAM. Assign the CHR banks like so: $0000=0, $0800=2, $1000=4, $1400=5, $1800=6, $1C00=3. Then your animated tiles can be put in $0C00-$0FFF and they'll be mirrored to $1C00-$1FFF.
3gengames: I've gathered from qbradq's recent posting history that a new mapper is easier said than done.
tepples wrote:
But as I understand it, CHR A10-A12 goes through the MMC3 even with CHR RAM.
True, I had forgotten about this.
Quote:
Assign the CHR banks like so: $0000=0, $0800=2, $1000=4, $1400=5, $1800=6, $1C00=3. Then your animated tiles can be put in $0C00-$0FFF and they'll be mirrored to $1C00-$1FFF.
That's an interesting idea, and the closest thing to a solution for this issue. I'd have to try and see if I could map everything I want that way. Thanks for the suggestion.
tokumaru wrote:
If it weren't for the incompatibility between the scanline counter and 8x16 sprites using tiles from both pattern tables I'd totally agree with you. That limitation is a deal breaker for me.
And so we can conclude that FME-7 with 32K CHR-RAM = perfect mapper.
thefox wrote:
And so we can conclude that FME-7 with 32K CHR-RAM = perfect mapper.
To me it almost is! The only problem is that we need different IRQ counter values for NTSC and PAL, but since we already have to worry about music and other things, so this isn't much of a problem at all.
tepples wrote:
Assign the CHR banks like so: $0000=0, $0800=2, $1000=4, $1400=5, $1800=6, $1C00=3. Then your animated tiles can be put in $0C00-$0FFF and they'll be mirrored to $1C00-$1FFF.
Hey tepples, just wanted to thank you again for this suggestion. Even though this solution isn't ideal (after all I end up losing some space because of the tile redundancy), it actually reduces the amount of frustration I have towards the MMC3.
At this point I don't think I'll change my project to MMC3, but I'd surely consider it for a future project. Even if I decide to use CHR-ROM instead of CHR-RAM, this idea should still work well, with 1 1KB slot dedicated to the main character, 2 for level objects and enemies and the last one (mostly) for animated objects. On the BG side, the remaining of the animated 2KB section could be used for level-specific animations.
Glad I could help. I wonder how many existing MMC3 games use 8x16px sprites and map one page into both pattern tables.
Do most emulators support CHR-RAM banking in MMC3? I did a test ROM but can't remember the results and I've lost the code in a HDD crash.
I did a quick Mega Man 4 hack (I messed up the code that initializes the CHR banks) and indeed graphics got screwed up in all emulators I tested (FCEUX, Nestopia and Nintendulator), so it's safe to say that at least these support this feature.
I guess the emus will switch the banks if you write something to the banking registers, but they will default to the regular "0,1,2,3,4,5" bank switching if you do nothing, while the real MMC1 will default to "0,0,0,0,0". So if yo actually want to use the CHR-RAM like a plain 8KB RAM, you should first do some bank switching at startup so that it is set up correctly.
It was Banshaku if I remember well who had this problem, his program worked fine in all emus, but failed on a real cart because of that.
Yup, you have to initialize the mapping with sequential numbers if you want to use the memory contiguously.