gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Coding > Map compression

#3223 - DekuTree64 - Thu Feb 20, 2003 5:20 pm

How do most overhead scrolling games store their map data? I was thinking about doing a system where the maps are cut into 16x16 tile blocks (using 8x8 px tiles), and compressed with LZ77 (not the graphics, the screen data). Then decompressing the 9 nearest blocks to EWRAM, so when say you move to the right, and the center block goes off screen, then the left 3 are discarded and 3 new ones are loaded on the right.
But then I got to thinking, and realized that SNES didn't have the procesing power and memory to do something like that, so there must be a better way that I'm not thinking of.

So would anyone like to share some ideas on the matter?

#3230 - tepples - Thu Feb 20, 2003 7:06 pm

Some initial Game Boy games used 8x8 pixels as the map granularity because artists were just beginning to come to grips with a screen 160 pixels wide instead of 256, but most Game Boy, NES, and Super NES games used "meta-tiles", squares of 2x2 to 4x4 hardware tiles. For example, the [?] block in Super Mario Bros. is a 16x16 pixel meta-tile of 2x2 HW tiles. Contra for NES used 32x32 pixel meta-tiles. Kirby Super Star was an oddball using 24x24 pixel meta-tiles, but it was trying to emulate the screen proportion of Kirby's Dream Land for GB (10 meta-tiles wide) in response to criticism that the graphics of Kirby's Adventure (NES version of Kirby: Nightmare in Dream Land) were too small.

The Legend of Zelda used "positional encoding" (rectangle of rocks at (x,y)-(x2,y2), rectangle of water at (x,y)-(x2,y2), individual rock at (x,y), enemy spawn points at (x,y), etc.

If you don't already have a firm design of the level layouts and the limitations you can impose on the levels (e.g. SMB1 three objects per column), I'd recommend using these in a free overhead scroller: Each map has 16x16 spaces, where each space corresponds to a 2x2 square of HW tiles. Store each map with RLE compression (LZ77 isn't likely to help much in this case), and keep four maps in memory at once.

How big is your overworld?
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#3236 - DekuTree64 - Thu Feb 20, 2003 9:31 pm

Thanks for the tips. I was thinking 16x16 tiles would probably make the biggest difference, but that would be a lot of work to change in my map editor, and would take more VRAM too, since 8x8 tiles are much more flexible, so I can use the same few to make different looking rocks and trees and things. Actually 16x16 tiles would save a lot of time drawing maps too.
I think I will go with my original idea though. No point in restricting things if the GBA is strong enough not to^^
I will try both LZ77 and RLE though. LZ77 should help a lot with repetitive grass and things (since I have 16x16 grass tiles chopped into 4 pieces anyway), but it might be too slow, and RLE should be fine on layers with a lot of transparent tiles.

#3237 - tepples - Thu Feb 20, 2003 10:23 pm

DekuTree64 wrote:
16x16 tiles would probably make the biggest difference, but that would be a lot of work to change in my map editor

That's why I don't hardcode 8x8 pixels when loading tile sets in my map editor.

Quote:
and would take more VRAM too, since 8x8 tiles are much more flexible, so I can use the same few to make different looking rocks and trees and things.

You can reuse VRAM tiles in multiple different meta-tiles. Look at how Super Mario Bros. for NES and GBC draws clouds, the edges of hills, etc.

Quote:
No point in restricting things if the GBA is strong enough not to

If you make the map data smaller, you can use e.g. higher quality voice samples, or more frames for a character's walk animation (a deficiency that has almost reached clich? status in 16-bit RPGs), etc.

Quote:
I will try both LZ77 and RLE though.

Consider that RLE is simply the special case of LZ77 where the match distance is always equal to one. RLE isn't likely to beat LZ77 unless you have some REALLY long runs, as GBA RLE can compress runs of up to 128 bytes into two coded bytes, while GBA LZ77 is hard-limited to 8:1 compression (eight 18-byte runs encoded into a 17 coded bytes).

Quote:
(since I have 16x16 grass tiles chopped into 4 pieces anyway)

The secret of data compression is to model the data in such a way as to remove as much correlation as possible before you send the data to a general-purpose lossless codec. For instance, in this case, you have 16x16 grass chopped into 4 pieces, and you're trying to store each piece with a separate tile number. You now have correlation between two bits of the grass tile number and two bits of the (x, y) vector. To remove this correlation, I'd store one map value for "grass" and then reconstruct 16x16 grass at runtime, choosing which tile to use based on the (x,y) coordinates.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#3283 - DekuTree64 - Fri Feb 21, 2003 7:28 pm

tepples wrote:
That's why I don't hardcode 8x8 pixels when loading tile sets in my map editor.

I really didn't have much of a clue what I was doing when I wrote my map editor, so I hardcoded it for simplicity. Turns out it's pretty easy to change though

Quote:
You can reuse VRAM tiles in multiple different meta-tiles. Look at how Super Mario Bros. for NES and GBC draws clouds, the edges of hills, etc.

Come to think of it, yeah, and that means I can make tons of combinations using the same tiles, so it will look about the same.

Quote:
If you make the map data smaller, you can use e.g. higher quality voice samples, or more frames for a character's walk animation (a deficiency that has almost reached clich? status in 16-bit RPGs), etc.

True, but more frames=more time drawing them, and thus fewer different NPCs as I become increasingly lazy. The whole reason I posted this was because I needed memory for more maps though, so I will go with your method after all.
Many thanks for your help, and for all the other good stuff I've read in your other posts around the board^^

#3292 - mbcook - Fri Feb 21, 2003 8:39 pm

You could keep each world compressed on the cart, and keep some ram open to hold the map. Then when you go to one world, during the "loading" screen or animation or whatever, you can use that time to decompress the world into ram. This way you could have a couple of large worlds, but don't have to deal with decompressing things on the fly. This would have it's drawbacks though. For example, you couldn't just have one HUGE overworld (ala Lenny Walkabout), you'd have to sort of partition it with little sections (sorta like Zelda: A Link To The Past does). Just an idea, you can ignore me ;)
_________________
--Michael