Tiles

Overview Creating bitmaps for tiles Loading tile bitmaps Rebuilding tile bitmaps

Overview Purple Martians is a tile based game. Each tile is 20 x 20 pixels. (A design decision made in 1997) Each level is 100x100 tiles or 2000 x 2000 pixels. The tiles are stored in arrays of bitmaps and accessed by the array indexes. From the very beginning in 1997 up until 2017, the tiles were 256 color, 8 bit bitmaps. I made my own bitmap and palette editor and drew all my bitmaps with those tools. I ended up making my own custom palette with 15 colors, each color being faded 16 times. I used to save and load tiles to disk one get_pixel and one put_pixel at a time. I'm kind of embarassed to say I continued to do that up until 2017! I finally converted the whole project to 24 bit color in 2017. The main push to convert came from all the work arounds I had to do in Windows 7. 8 bit color does not render properly in full screen modes with Allegro 4. (although windowed mode was fine) And now in Allegro 5, its just not supported at all. Unfortunately, my bitmap and palette editor did not survive the conversion. Now I have to use an external editor like gimp. I used to store different colorized versions of players and doors with the main tiles. I have since converted door and player tiles to have their tilemap files. The 3 tilemaps are stored in the bitmap/ folder:

    tiles.bmp        (1024 main tile storage)
    player_tiles.bmp (16 colors x 19 shapes)
    door_tiles.bmp   (16 colors x 8 shapes x 2 door types)

I load these from file only once when the game starts. They are stored here as video bitmaps:

    al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA);
    al_set_new_bitmap_flags(ALLEGRO_NO_PRESERVE_TEXTURE | ALLEGRO_VIDEO_BITMAP);
    tilemap  = al_create_bitmap(640, 640);
    ptilemap = al_create_bitmap(380, 320);
    dtilemap = al_create_bitmap(160, 640);

They are also stored here as memory bitmaps so that I can re-store the video bitmaps if the screen changes.

    al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA);
    al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
    M_tilemap =  al_create_bitmap(640,640);
    M_ptilemap = al_create_bitmap(380,320);
    M_dtilemap = al_create_bitmap(160,640);

I use sub-bitmaps created from the video bitmaps so that I can draw with indexes:

    ALLEGRO_BITMAP *tile[NUM_SPRITES];
    ALLEGRO_BITMAP *player_tile[16][32];
    ALLEGRO_BITMAP *door_tile[2][16][8];

Creating bitmaps for tiles - called only once from 'initial_setup()'

    void create_bmp(void)
    {
       // create tilemap bitmaps
       al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_32_WITH_ALPHA);
       al_set_new_bitmap_flags(ALLEGRO_NO_PRESERVE_TEXTURE | ALLEGRO_VIDEO_BITMAP);
       tilemap = al_create_bitmap(640, 640);
       ptilemap = al_create_bitmap(380,320);
       dtilemap = al_create_bitmap(160,640);

       // create memory bitmaps as temp storage for restoring tilemaps after screen change
       al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
       M_tilemap = al_create_bitmap(640,640);
       M_ptilemap = al_create_bitmap(380,320);
       M_dtilemap = al_create_bitmap(160,640);
    }

Loading tile bitmaps - called only once from 'initial_setup()' - tilemaps are loaded from files - M_tilemaps are created from tilemaps - sub_bitmaps are created from tilemaps

    int load_tiles(void)
    {
       // get main tiles
       tilemap = al_load_bitmap("bitmaps/tiles.bmp");
       if (!tilemap) m_err("Can't load tiles from bitmaps/tiles.bmp");
       else
       {
          al_convert_mask_to_alpha(tilemap, al_map_rgb(0, 0, 0)) ;
          al_set_target_bitmap(M_tilemap);
          al_draw_bitmap(tilemap, 0, 0, 0);
          for (int y=0; y<32; y++)
             for (int x=0; x<32; x++)
                tile[y*32 + x] = al_create_sub_bitmap(tilemap, x*20, y*20, 20, 20);
        }

       // get player tiles
       ptilemap = al_load_bitmap("bitmaps/player_tiles.bmp");
       if (!ptilemap) m_err("Can't load tiles from bitmaps/player_tiles.bmp");
       else
       {
          al_convert_mask_to_alpha(ptilemap, al_map_rgb(0, 0, 0)) ;
          al_set_target_bitmap(M_ptilemap);
          al_draw_bitmap(ptilemap, 0, 0, 0);
          for (int a=0; a<16; a++)
             for (int b=0; b<19; b++)
                player_tile[a][b] = al_create_sub_bitmap(ptilemap, b*20, a*20, 20, 20);
       }

       // get door tiles
       dtilemap = al_load_bitmap("bitmaps/door_tiles.bmp");
       if (!dtilemap) m_err("Can't load tiles from bitmaps/door_tiles.bmp");
       else
       {
          al_convert_mask_to_alpha(dtilemap, al_map_rgb(0, 0, 0)) ;
          al_set_target_bitmap(M_dtilemap);
          al_draw_bitmap(dtilemap, 0, 0, 0);
          for (int a=0; a<16; a++)
             for (int b=0; b<8; b++)
             {
                door_tile[0][a][b] = al_create_sub_bitmap(dtilemap, b*20,     a*20, 20, 20);
                door_tile[1][a][b] = al_create_sub_bitmap(dtilemap, b*20, 320+a*20, 20, 20);
             }
       }
    }

Rebuilding tile bitmaps The tilemap bitmaps are rebuilt if the display changes and their contents are lost. This is done by drawing the memory bitmaps (M_tilemaps) to the video bitmaps (tilemaps). The sub_bitmaps do not need to rebuilt, just their parents. This is only called from 'proc_screen_change()'

    void rebuild_bitmaps(void)
    {
       al_set_target_bitmap(tilemap);
       al_draw_bitmap(M_tilemap, 0, 0, 0);

       al_set_target_bitmap(ptilemap);
       al_draw_bitmap(M_ptilemap, 0, 0, 0);

       al_set_target_bitmap(dtilemap);
       al_draw_bitmap(M_dtilemap, 0, 0, 0);
    }