2
\$\begingroup\$

I'm trying to load a tile-based map in my game. I've been watching SDL tutorials for a while now but they never covered how to represent the map in a file? How can I represent a tile map on-disk in a way that also lets me store information about collision and other properties?

\$\endgroup\$
4
  • \$\begingroup\$ Is there a specific way you're representing tile maps on the disk that you're having trouble with? Or are you unsure of how to represent tile maps on the disk? \$\endgroup\$
    – user1430
    Commented Mar 21, 2016 at 15:30
  • \$\begingroup\$ @JoshPetrie I am unsure of how to represent tile maps on the disk and how to detect collision on the tile maps. \$\endgroup\$ Commented Mar 21, 2016 at 16:02
  • \$\begingroup\$ It's probably worth asking the collision question separately. Since we don't permit questions asking for tutorials I changed your question to ask specifically about representing the map in a way that would let you still store collision info, which you could ask about in a new post. \$\endgroup\$
    – user1430
    Commented Mar 21, 2016 at 16:07
  • \$\begingroup\$ I would suggest you look into the specifications of the Tiled TMX map format. Maybe you'll get inspired :) \$\endgroup\$
    – Vaillancourt
    Commented Mar 22, 2016 at 13:08

4 Answers 4

1
\$\begingroup\$

There are several well-used methods.

One of the simplest, to implement and to work with, is to use some sort of text grid, used in a lot of roguelikes. Here's an example from puzzlescript:

=======
LEGEND
=======

. = Background
# = Wall
P = Player
* = Crate
@ = Crate and Target
O = Target

=======     
LEVELS
=======

#########
#.......#
#.....@.#
#.P.*.O.#
#.......#
#.......#
#########

Each tile is represented as a single character in a plain text file. One advantage is that you can edit levels using a text editor. You can also use lots of different characters to represent different tile types, so there's some amount of flexibility.

Sometimes you have lots of tile types/properties and not enough ASCII characters to represent them, so another approach is to use tile IDs. That is, each tile is represented by an ID number, and the entire map is a 2D array of these numbers, followed by tile definitions. So you might have:

1,1,1,2,256,190,...
3,5,7,3,0,0,0,...

1 = Wall
2 = Floor
3 = Grass
256 = Excalibur
...

This is how Tiled does it; the actual file could be XML, JSON, or anything that can represent 2D arrays.

Sometimes you could have gigantic maps; imagine a tile-based space game where most of the space is empty but the map is massive. Representing it as a 2D array would be impractical - a 1 million squared map would take one trillion elements to represent. Here you may want to go with something like a sparse matrix storage, i.e. you only store where interesting tiles are, and not the whole map. There are also certain procedural generation techniques you can use to cut down on storage requirements.

\$\endgroup\$
3
  • \$\begingroup\$ How would you handle stacked elements? E.g. a tree over a grass tile. \$\endgroup\$
    – Ignorant
    Commented Apr 3, 2017 at 10:50
  • 1
    \$\begingroup\$ Multiple layers \$\endgroup\$ Commented Apr 3, 2017 at 11:50
  • \$\begingroup\$ Puzzlescript does it by assigning each object to a layer. The example shows @=create and target. Very powerful technique. \$\endgroup\$
    – david.pfx
    Commented May 10, 2018 at 7:16
0
\$\begingroup\$

Loading the tile map has many different possibilities. Probably the most common is an XML file, but I personally dislike XML files because they are way bigger than they need to be. What I do 95% of the time for this, is have a text file that does a diagram of it. Here is an excerpt from a tile map in one of my own games.

~begin
~enemy_rate 50
#               
#               
#               
#       ###     
####            
#               
#               
#               
#               
#               
########        
#               
#               
#               
#       ^       
################
~end

They are extremely easy to read with the human eye, extremely fast to load because they are just .txt files, and quite versatile. As you can see, ~begin, means that it is the beginning of a tile map, ~enemy_rate is a parameter I use to specify things about that map, and ~end means that it is the end. I can have as many of those I want in a file, since they have beginnings and endings in the file.

However, since this is ASCII, you are limited to a total of ~93 different possible drawn ASCII characters. For most cases, 93 different tiles is more than enough, and you could make modifiers, but something to consider.

As for checking for collisions, I have a really basic version in C++ that does this exact job, but it's not perfect. This is what it looks like:

bool GameRoom::checkCollision(double x, double y, GameObject * object)
{
    return (getCollGrid((x + object->hitBoxX1) / wallWidth, (y + object->hitBoxY1) / wallHeight) != 0 ||
        getCollGrid((x + object->hitBoxX2) / wallWidth, (y + object->hitBoxY1) / wallHeight) != 0 ||
        getCollGrid((x + object->hitBoxX1) / wallWidth, (y + object->hitBoxY2) / wallHeight) != 0 ||
        getCollGrid((x + object->hitBoxX2) / wallWidth, (y + object->hitBoxY2) / wallHeight) != 0);
}

In this example getCollGrid(x, y) returns the value at (x, y) position; and checks that it isn't 0. I use that in an example game, so it does work.

\$\endgroup\$
0
\$\begingroup\$

What you are trying to do is storing a grid of numbers into an array, there is unlikely to be one, best solution. We've used Paolo's example for some projects.

For others we've used something as simple as a bitmap where eacht pixel's color meant a different tile-type. The tile-type determined the properties of the tile. This made the map easy to observe and edit with basic image editors. You could decide to store aditional information in different color channels or in an accompanying file.

\$\endgroup\$
0
\$\begingroup\$

TL;DR MsgPack

Long one

I developed a game and asset management library in ActionScript using msgpack. Msgpack -as its slogan says- is like json but... smaller. msgpack is available on a lot of languages, like C and C++. This is the repository.

There is a counterpart here: although the people recommending me this format was the Python group, I never heard about it before, so I don't know how maintained is right now, but it never failed me.

Another alternatives with their caveats:

  1. XML: Usually good and human readable, but pretty heavy for your porpose.
  2. JSON: Better than XML, readable almost like XML, but still heavy.
  3. Plain array or custom format: The best it can be depending on how good are you coding the serializer and deserializer for it.

I think you will have several layers here (tiled map games have several layers for floor, decals, objects to pick, objects to collide against, ceilings, extra effects like clouds... you choose). My suggestion is to think the format carefully, and pack the objects using msgpack as a bidimensional array [x,y] or small arrays [layer]. This means, somewhere you will have something like this:

uint width = 100;
uint height = 100;
uint FLOOR = 0;
uint DECALS = 1;
uint PICKABLE = 2;
uint COLLIDERS = 3; //players and other colliding objects would be here
uint CEILING = 4;
uint EXTRA = 5;
uint[,,] map = new uint[width, height, 6];

map[0,0,3] = (numerical id for your player);

//YOUR NEXT TASK IS TO SERIALIZE AND SAVE THIS MAP VARIABLE INTO A FILE.
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .