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 > Worms-type game ; makin' holes!

#31350 - kiwibonga - Fri Dec 10, 2004 8:08 am

I'm making a GBA version of Gunbound (http://www.gunbound.net). It's a worms style game, with some RPG elements. Some people say it's close to Scorched Planet, I haven't played that though, so I wouldn't know..

Anyways... The project just started, and I'm already facing some problems :P

Here's the deal, with a worms-type game, when a missile lands, it makes a hole, a hole that the characters can walk into, a hole that the player can see. The hole is basically a transparent color filled-oval drawn over the background.

But here's the deal. The WHOLE background is destructible, this means that I need to keep track of every single pixel that has been destroyed! Even worse, the maps are bigger than one screen in size, so I can't just draw holes to the screen, I have to keep track of them even when they're off screen..

Obviously, keeping a big 256 color bitmapped background in memory isn't really efficient if you have to scroll. I was able to make a scrolling bitmap BG by making this function that copies an area of a 480x320 bitmap in ROM to VRAM using DMA, it was fast enough but it's definitely not a good idea if you have to redraw the holes every time it's scrolled, even if you're using a bit mask or whatever.

So what I have now is a tiled BG, with only unique, 16 color tiles, except for transparent tiles of course.

What I want to do is directly modify the tiles by copying a rectangle from the background to a bitmap array, drawing the oval to that bitmap, and then writing to the tiles.

Problem is... 4 bits per pixel means each byte is a pair of pixels, even worse, the highest 4 bits code for the right pixel, and the lowest 4 bits for the left pixel.

So basically I would have to save an array of tile numbers, copy each tile 8 pixels at a time to a bitmap "canvas," not forgetting to pick out the higher and lower 4 bits of each byte and storing them in a char array.. Then I'll draw my oval, and do the conversion backwards, and finally write the tile data back...

In short, I need help with this because it's a huge headache to plan, and I'm sure something is gonna go wrong!

How it would go if I did it:

(assume that the missile's landing point is the top left of the oval hole's rectangle bounding box, for simplicity, if that helps at all....)

missile lands at landx,landy
tile position: landxt = landx/8, landyt = landy/8
width and height of the explosion: exwidth, exheight
same thing but in tiles: exwidtht = ceiling(exwidth/8), exheightt = ceiling(exheight/8)
temporary bitmap to draw the explosion oval to: u8* tempBg = malloc(exwidtht * 8 * exheightt * 8)
temporary array that contains tile numbers: u16* tempTiles = malloc(exwidtht * exheightt * 2)

[loop to list the tile numbers in the specified region and store them into the tempTiles array]

[loop to fetch each tile and draw it to the temporary bitmap]

[call the function I made to draw an oval to the temporary bitmap]

[loop to write each tile to the appropriate position in VRAM]

And... we're done. It looks simple huh?

Questions:

- Do you know a quick way to convert a 4bpp bitmap with reversed half-bytes to a 8bpp bitmap? The way I see it I'll have to take each byte, AND it with 0F, save the result, then AND it with F0, shift it 4 bits to the right, save it to the next value, repeat 4 times, write that 8 pixel line to the bitmap, and do that 8 times in total for just one tile... Is there a simpler way to do it?

- Better yet, do you know a way to directly draw something to the tile data? I'm having tremendous trouble visualizing how to even draw a rectangle to the tile data without converting it, storing it temporarily in something more linear, and converting it back and writing it... It would be so much simpler if the tileset was just this big bitmap, and not 32 byte strings tile after tile...

- Is my idea total crap?

- Ultimate question: is there already a worms style homebrewn game with source out there which does exactly what I'm trying to do? :P

And well, that's about all I wanted to ask... Thanks a bunch to anyone who can help me out ^^
_________________
http://www.kiwibonga.com

#31375 - _pluto9 - Fri Dec 10, 2004 5:50 pm

I have an idea... you could use 8x8 tiles. It wouldn't be to pretty, but it'd work... and if your really feeling adventurous you could use different types of tiles (for edges and corners and diagonals), and then write an algorithm to "smooth out" your map. (if you remeber how the Warcraft II map editor works)

....

I did a little thinking, and came up with an algorithm that *might* work (I didn't test it, I'm at school)

Code:
for (x=0; x<mapsizex; x++)
   for (y=0; y<mapsizey; y++)
      if (map(x,y)>0)
      {
         int top=1, bottom=1, left=1, right=1;

         if (map(x+1, y)>0)
            right = 0;
         if (map(x-1, y)>0)
            left = 0;
         if (map(x, y+1)>0)
            bottom = 0;
         if (map(x, y-1)>0)
            top = 0;
         
         /*if (left && right && top)
            top = 0;
         if (left && right && bottom)
            bottom = 0;
         if (top && bottom && right)
            right = 0;
         if (top && bottom && left)
            left = 0;*/

         map(x, y) = top + bottom<<1 + left<<2 + right<<3;
         //        = top + bottom *2 + left *4 + right *8;
      }


now of course you'll have to arrange your tiles in the right way for this... (just look at the second last line of code). The top,bottom,left,right variables indicate that the tile comes to a point at that position

#31409 - sajiimori - Fri Dec 10, 2004 9:14 pm

Using a tile BG, the number of tiles that are partially destroyed should be small compared to the number that are either untouched or totally destroyed.

Going by that theory, here's my suggestion:

Have the pixel data and map in ROM.

Make an array with 2 bits per tile, with enumerations for untouched, destroyed, or bitmasked.

Allocate space for a limited number of bitmasked tiles, due to probable RAM limitations. Each entry is 8x8 bits. Entries can be allocated on demand, and are freed when a tile changes to the "destroyed" state.

When you run out of bitmask entries, sadly you'd have to go straight to "destroyed" which would result in hard angles. Allocate enough entries so you probably won't have that problem during an average battle. Such is life on limited hardware.

#31572 - AnthC - Sun Dec 12, 2004 11:23 am

Just my suggestion

Assuming a 160x240 screen is about 600 tiles.
I would map the screen as linear tile arrays and modify the strip that is coming on and off the screen when scrolling.

So your screen would look like this in tile numbers :-

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
30 31 etc.
60 61 etc...
etc..
etc..

So when you scroll your screen left, you would modify your vertical strip of tiles (on the right) 29 59 89 etc.
Now this leads to the problem of destroyed tiles.
How I would handle this is by having a 1 bit mask in ram that represents each pixel in your map and 'cookie cut' chunks out of this and modify the respective tiles on screen. Each 'mask screen' would take up 160*240/8 bytes in RAM (about 4.7k) so you have room for about 54 screens in slow RAM which is quite a large amount.
When you blast chunks out of your map you simply cookie cut bits out of the mask and modify the on screen tiles.
If you need more screens then you could tile your RAM and remove the blank areas but that would be more complex and need better handling.

You might need a bigger tile area for scrolling (extra column and row) so you you hide the scrolling section but you get the general idea.

#31588 - sajiimori - Sun Dec 12, 2004 7:35 pm

...which is basically my suggestion except slower and more RAM hungry. But if it's good enough, then go for it.