Page 1 of 1

Buffering level/background data question

Posted: Mon Mar 13, 2017 5:39 pm
by gravelstudios
Hello. I'm new here. I'm sorry if this is a question that has been answered before. If so, please feel free to point me to the correct thread.

I've already programmed a game that has a non-scrolling background, similar to a pac-man maze, which is the same for every level. I'd like to start work on a game that scrolls. I have a basic scrolling engine going that stores level data using RLE compression, decompresses that data on the fly, and sends it to the PPU so that as the screen scrolls left and right, it displays the correct new background tiles. I've pretty much figured out 'the seam' and swapping nametables.

In my first game, the level data is stored as data bytes in the rom. wall collision is handled by a routine that converts the sprites' coordinates into the relevant address in the table, and checks to see what type of tile it is, whether it's 'solid' or not. This method only works because the background data is not compressed. As far as I can tell, there is no really efficient way to perform this kind of check on compressed level data.

The NES doesn't really have enough RAM to decompress two entire screens' worth of tiles into a buffer for doing this kind of collision checking. I got it down to two pages with the use of 16*16 metatiles. My basic question is whether I'm using the right approach. Is there a better way to decompress level data, perform wall collision detection with sprites, and then load data into the nametables at the seam? Do I have to use two entire pages of RAM for this, or is there a way to do it with less? Thanks for any advice.

Re: Buffering level/background data question

Posted: Mon Mar 13, 2017 5:55 pm
by tepples
gravelstudios wrote:The NES doesn't really have enough RAM to decompress two entire screens' worth of tiles into a buffer for doing this kind of collision checking. I got it down to two pages with the use of 16*16 metatiles. My basic question is whether I'm using the right approach.
Your approach is workable. Super Mario Bros. decompresses its levels to two 16x13-metatile pages. It uses them as circular buffers for collision data, writing a column at a time as the player progresses through each level. There are other ways, such as multi-level metatiles that allow random access to any part of a level (as seen in Mega Man, Blaster Master, and 16-bit Sonic the Hedgehog), but these don't allow quite as much destruction of a level (such as Mario breaking bricks).
Do I have to use two entire pages of RAM for this
What other uses did you have planned for the RAM?

Here's how an NES platformer might arrange RAM:
  • $0000-$00FF: Commonly accessed global and actor variables
  • $0100-$01BF: VRAM transfer buffer
  • $01C0-$01FF: Call stack
  • $0200-$02FF: Sprite display list
  • $0300-$037F: Music engine state
  • $0380-$03FF: Less commonly accessed global variables
  • $0400-$05FF: Metatiles for two screens of the map
  • $0600-$07FF: Actor variables
Previous discussion about collision map memory use

Re: Buffering level/background data question

Posted: Mon Mar 13, 2017 6:37 pm
by tokumaru
In most games, the smallest blocks used to compose the level map are not 8x8 pixels, but often 16x16 and sometimes even 32x32 pixels (e.g. lots of Capcom games). The 8x8 tiles are then just the smallest graphical entity used to draw levels, but the physical blocks that build the levels and objects interact with are larger. At those sizes, it becomes more practical to store decompressed sections of the levels in RAM.

Also, whether or not you can test for collisions directly against compressed maps in the ROM will depend of the actual compression format. Something compressed with RLE or LZ obviously can't be randomly accessed, but nested metatiles for example can. In the Mega Man games, for example, levels are composed of screen-sized blocks (256x256 pixels), each made of 32x32-pixel blocks. That kind of scheme would be easy to read right off the ROM, while still using only 64 bytes per unique screen, which is fairly compact.

Re: Buffering level/background data question

Posted: Mon Mar 13, 2017 8:06 pm
by rainwarrior
gravelstudios wrote:The NES doesn't really have enough RAM to decompress two entire screens' worth of tiles into a buffer for doing this kind of collision checking. I got it down to two pages with the use of 16*16 metatiles. My basic question is whether I'm using the right approach. Is there a better way to decompress level data, perform wall collision detection with sprites, and then load data into the nametables at the seam? Do I have to use two entire pages of RAM for this, or is there a way to do it with less? Thanks for any advice.
If the only information you need to store per-tile is "solid" and "not-solid", then you can pack 8 tiles per byte (each one in a separate bit). You'd only need 64 bytes to store 2 x 16 x 16 tiles this way.

Re: Buffering level/background data question

Posted: Tue Mar 14, 2017 2:44 am
by gravelstudios
Thank you all for your advice. I am storing level data as 16x16 pixel blocks, using the last two bits of each 'block number' for the palette that's supposed to go with that block. My scrolling engine works fine, but I just wanted to know if I was using the correct techniques to do all this. I guess there is no 'right' way as long as it works.

By the way, does anybody know how Metroid does this? I know that Metroid stores rooms and objects of various sizes, but how does it decompress level data and perform wall collision?

Re: Buffering level/background data question

Posted: Tue Mar 14, 2017 12:57 pm
by OmegaMax

Re: Buffering level/background data question

Posted: Tue Mar 14, 2017 4:02 pm
by AWJ
gravelstudios wrote:Thank you all for your advice. I am storing level data as 16x16 pixel blocks, using the last two bits of each 'block number' for the palette that's supposed to go with that block. My scrolling engine works fine, but I just wanted to know if I was using the correct techniques to do all this. I guess there is no 'right' way as long as it works.

By the way, does anybody know how Metroid does this? I know that Metroid stores rooms and objects of various sizes, but how does it decompress level data and perform wall collision?
Like several games that were ported from FDS to cartridge, Metroid has an extra 8KB of RAM on the cartridge.

Re: Buffering level/background data question

Posted: Tue Mar 14, 2017 4:27 pm
by gravelstudios
AWJ wrote:Like several games that were ported from FDS to cartridge, Metroid has an extra 8KB of RAM on the cartridge.
Based on the source code, it looks as if Metroid uses 2 kilobytes of cartridge RAM to store 2 complete nametables' worth of 8x8 tiles. Thanks for helping me answer my own question.