Game Tile Map Question

I am working on a game tile map. I found this thread http://www.cplusplus.com/forum/general/18315/ very helpful!

A few things were left out in that thread, and I just want to make sure I am going about this the right way. I would like to create something that I could use for other programs, and also that any other developer could easily use and modify if the map needed to be adjusted, more levels added, images changed etc.

One of the challenges I will face is that while all of my tiles are the same size (96x96) they each have different amounts of empty background space. So for collision detection, I think I will need to understand where the border of the image is as well.

I am new to C++ programming, so please critique my approach and let me know if it sounds like I am going about this the right way.


My plan is as follows:

Step 1

Create 13 separate structs for the different types of tiles that I have in my set.
The structs will look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct tile {
  bool is_solid;
  
  // The corners will represent the edges of the tile
  int  n_corner;
  int  w_corner;
  int  e_corner;
  int  s_corner;

  // Because the images do not always reach the edge, I am 
  // recording where the image ends, for collision detection
  int  n_border;
  int  w_border;
  int  e_border;
  int  s_border;
} ;


Step 2

Enumerate some integers to make it easier to understand what is on
the map. Example

1
2
3
4
5
enum tiletypes {
NW = 0, 
HO = 1, 
GR = 2, 
etc};


Step 3

Create a one dimensional array of integers that I can use as a visual
representation of my tile map (my example is enumerated):

1
2
3
4
5
6
7
8
int height = 9;
int width = 11;
int tilemap[height*width]{
NW, HO, HO, HO, HO, HO, HO, HO, HO, HO, NE, 
VE, GR, GR, GR, GR, GR, GR, GR, GR, GR, VE,
etc.
}
;


Step 4

Create a function that accepts a pointer to an array of integers,
a pointer to an array of sprite objects, and a reference to the tilesheet
image.
NOTE: I am using the SFML graphics library which is where the sf:: comes from.

1
2
3
4
5
6
7
8
void create_map(int* tilemap, sf::Sprite* spriteArray, sf::Image& tilesheet)
{
/* 
The body of the function will then loop through the tilemap, set the
inner rectangle of each sprite from the coordinates specified by the struct, set
the position for each tile, and use a nested loop to create the separate rows
*/
}


Does this sound like the best approach?
Last edited on
It sounds like this will work well enough. One concern I have is that you sound like you're using image data for collision detection, which is typically a bad idea. Collision and graphics are usually better off as two separate systems.

This also makes the collision detection quite a bit more complicated than it probably needs to be.

Collision is much, much simpler when the entire tile is all-or-nothing. Either it's solid or it isn't. When you start having tiles that are half solid, or only partially solid it gets tricky. 96x96 is also pretty large for an underlying tile, which is partially why you're having to split up your tiles into "partially solid". I would probably break the tiles down to a size where you can have them fully solid/open.

If you still want to design your map as if it were 96x96 tiles, you can. The technique is called "meta tiles" and it's very common in older games. It also serves as a basic form of compression.

Basically, instead of your map file having an index to a specific tile, it has an index to a metatile. You then have a list of metatiles which tell you how to "build" each metatile.

A simple example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// for this example, let's say your metatiles are 96x96 and your tiles are 32x32

int MetaTiles[][9] = 
{
  { // tile 0:  fully open
    0,0,0,
    0,0,0,
    0,0,0
  },{ // tile 1:  solid only in the bottom right corner
    0,0,0,
    0,1,1,
    0,1,1
  }
// .. etc 


Your map would internally hold the data for each individual tile -- as if your tiles were 32x32. You'd only need to "decode" the metatiles when you load the map. It would make loading a bit more complicated:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// assume 'width' and 'height' are the dims in 96x96 metatiles
int scale = 96 / 32;  // convert dims to actual 32x32 tiles
width *= scale;
height *= scale;

ResizeMap( width, height );

int mty, mtx;
for(mty = 0; mty < height; mty += scale)
{
  for(mtx = 0; mtx < width; mtx += scale)
  {
    int* mt = MetaTiles[ next_value_from_the_map_data ];
    for(int y = 0; y < scale; ++y)
    {
      for(int x = 0; x < scale; ++x)
      {
        SetTile( x + mtx, y + mty, mt[(y*scale) + x] );
      }
    }
  }
}



My $0.02
Thank You! That is exactly what I needed. I am going to go with your suggestion use some smaller tiles. I like the idea of all or none.

Topic archived. No new replies allowed.