[Wip] Zorg - Rougelike

I’m Having some trouble compressing the map into a manageable sized piece of memory It would be a great help if someone could lend a hand.

At the moment Ive managed a 20*20 Map with 16 block types

2 Likes

“ENumsThatArentActualyEnums.h”… Touché.

(Psst, @filmote, he’s on to you.)


Firstly, is the repo actually up to date?
Because Game.h is empty.

If it is up to date, how can you be sure you need to save memory when you’re not actually doing anything yet?

If it isn’t then you might want to do that to make sure the advice given is actually useful.


From the looks of what you’re trying to do with the shifting, your map is actually 40*20 tiles because each tile is a nibble, it’s just using 20*20 bytes.

First thing to address:

Block = Block << 4;
Block = Block >> 4;

I see what you’re thinking, but that’s actually more effort than what you need to do and actually probably generating more code than it needs to (I won’t bore you with the details of why unless you particularly want to know).

Instead you can just do:

Block &= 0x0F;

Likewise

Block = Block >> 4;
Block = Block << 4;

Can become:

Block &= 0xF0;

(If you don’t know about the bitwise operators &, | and ^, say so and I’ll explain.)

1 Like

Yes It Is empty since I want to get the map system running first.

Shouldnt it be 40*40 then?

Probably :confused:

Ok. In that case I think it’s a bit too soon to be looking for compressing and space saving. You’re already fitting two tiles per byte and that’s usually enough.
(It’s what filmote’s doing with Lode Runner and than runs just fine and so far it still has room left.)

Possibly?

Basically because you’re packing 2 tiles per byte on the horizontal axis the width in bytes is actually half of the width in tiles.

So if you wanted a map of 40x40 tiles you’d need 20x40 bytes,
if you wanted a map of 20x20 you’d need 10x20 bytes.

I’ll PM you the bitwise stuff because although it’ll probably be useful to other people who would stumble across it, it’s quite long and you’ll probably have questions or want more examples.

1 Like

In my Lode Runner game, I looked at how I can minimise the level size too.

They original had screens that were 28 x 16 wide. By packing them ‘two blocks per byte’ my average level was 250 bytes in size (including some additional player information).

I have since changed it to use a basic compression algorithm that simply works out ‘runs’ of the same block. I reserve the top 3 bits for the block type (as I only have 7 types) and lower 5 bits for the length. You are packing yours into half a byte you must have less than 16 block types.

if 0 = nothing, 1 = block, 2 = ladder then the following:

0x19, 0x02, 0x21, 0x03, 0x12, 0x02, 0x21, 0x03, 0x19

Renders out as:

BBBBBBBB
B  L   B
B  L   B
BBBBBBBB

My world has shrunk to 7 x 4 and used 9 bytes. In the older ‘two per byte’ it would be represented as:

0x11, 0x11, 0x11, 0x11, 
0x10, 0x02, 0x00, 0x01, 
0x10, 0x02, 0x00, 0x01, 
0x11, 0x11, 0x11, 0x11, 

Which is 12 bytes. The savings are greater than the 75% we gained here on bigger maps where there are significant runs of the same block. Some of my compressed levels actually ended up larger than the original as they were comprised of lots of single items. I actually cheated and used compression where it saved memory and the simple ‘two blocks per byte’ where it was smaller.

Here is my decompress code:

cursor = {memory address}

while (true) {

  uint8_t data = pgm_read_byte(&levelToLoad[dataOffset]);
  uint8_t block = (data & 0xE0) >> 5;
  uint8_t run = data & 0x1F;

  if (run > 0) {

    dataOffset++;

    for (uint8_t x = 0; x < run; x++) {

      if (cursor % 2 == 0) {
        _levelData[(cursor % 28) / 2][cursor / 28] = (_levelData[(cursor % 28) / 2][cursor / 28] & 0x0f) | (block << 4);
      }
      else {
        _levelData[(cursor % 28) / 2][cursor / 28] = (_levelData[(cursor % 28) / 2][cursor / 28] & 0xF0) | block;
      }

      cursor++;

    }

  }
  else {
      
    break;
      
  }

}

Note my _levelData array is defined as uint8_t [width][height].

2 Likes

Zorg is now in a Pre-release state with one generator working so far and player controls.
D-Pad - Moves player
A - Generates a new level

1 Like