0
\$\begingroup\$

Just a question regarding the storage of 2D map data. There are several topics discussed within gamedev, i.e. Array Storage: How to store 2D tile-map, custom map formats: A way to store potentially infinite 2D map data? etc

Considering that I intend to pre-generate my entire map at the start of the game (Much like Terraria does) and store that and then load 'chunks' of the data into an array or custom format as the player moves through it and interacts with the environment.

Been a total noob my question my be a little naive, but is there something wrong with pre-generating the map data (tile based, side view with each tile type represented as a discreet integer) as a PNG (No alpha) and saving that. Then read in the section of the PNG for the chunk to be loaded and converting the specific pixels to their integer value to determine what tile it represents ?

I could possibly even have one PNG for the terrain, one to represent containers and loot, which would be read separately and overlaid, then one for structures etc.

Then also obviously update the PNGs as terrain is created/destroyed by the player.

I can only assume this is not discussed anywhere as its probably slow versus maybe just reading/writing from/to a binary data format/array?

Regards John

\$\endgroup\$
2
\$\begingroup\$

Sure, you could do that, and it would not be "wrong" in the sense that any solution which gets you closer to a working game is never wrong.

But keep in mind that the PNG format is designed to store images for displaying them on a screen. You are using it for something it wasn't designed for. It might work, but you might get better results with a more tailor-made solution.

Which problems exactly does using the PNG format solve?

  1. Organize data into chunks
  2. Compress the data

First, chunk organization. Yes, the PNG format allows you to split the image data into individual IDAT chunks. You can retrieve individual chunks of the image by seeking over all those chunks which don't interest you. But this still requires to read the length-field of each chunk and seek over it to the next chunk until you've reached the chunk you want. So you still need to read a lot of the image file even if you only care about one single chunk. It would be better if you would have some data structure which tells you where to find each chunk. But that would be something you would have to build on your own.

Also, most PNG libraries do not assume that the user would care that much about how they want the chunk organization of their PNG to look. So getting your PNG encoder to organize the PNG file exactly the way you want might be difficult. You could of course write your own PNG encoder which organizes the IDAT chunks exactly the way you want, but then you can just as well invent your own file format.

And then you have to get your image decoder to get only that one chunk. This is again a very unusual use-case many libraries won't account for.

Or... maybe don't use chunks? Maybe your PNG library has a function like getImageData(x, y, width, height)? So why not use that to load just the data you want? Keep in mind that when all the image data is in one compressed chunk, then the library has only one way to implement this function: Read the whole image into memory, decompress the whole image, and then extract the section you want from the decompressed data. So in this case the PNG format would really get you no benefit at all.

Then, data compression. PNG uses the well-known DEFLATE algorithm to compress the IDAT chunks, which you can get just as easily as a free stand-alone implementation. Before applying DEFLATE, it can optionally apply one of several different filter methods in order to make the image data even more compressible. But these filter methods are all optimized for typical real-world image data. They are unlikely to improve the compression rate much when applied to non-image data.

So what do we learn from this? It might be easier to just roll your own map format:

  1. Compress each map-chunk to a byte-array using a stock compression algorithm of your choice (which might or might not be DEFLATE)
  2. Create an index which tells you order and length of the compressed chunks
  3. Write the index to the file, followed by the chunk data

If you want to retrieve a chunk, read the index (you might want to cache it in memory so you don't need to re-read it every time you load a chunk), jump straight to the position in the file it tells you, read it, and decompress it.

\$\endgroup\$
  • \$\begingroup\$ custom data structure it is then. Thanks for the quite comprehensive answers. \$\endgroup\$ – John Cogan May 12 '18 at 11:30
0
\$\begingroup\$

It depends. If you are not saving / loading the game often, then using an image for your save file isn't likely to be a barrier in terms of speed. On the other hand, if you are frequently doing automatic quick saves or check pointing, it may be a problem.

One advantage to your approach is that depending on the level size, it may give your players a fun & easy way to trade save game data. I don't recall the title, but there was some game that deliberately made the save game file a small thumbnail image of the level itself. Players could get a sense of what the level looked like at a glance, show off & trade levels on social media by posting the images & potentially edit the levels themselves with paint or photoshop (though not all such level might be valid).

The game MidBoss did something similar:

When a MidBoss player finishes a run—usually by dying—they can post a "death card" with the circumstances of their death or transcendence to Twitter. The embedded image doubles as a save files to allow other players to replay from the same seed or salvage loot from the failed run, since all of the information is steganographically encoded into the PNG image file.

Similarly, TerraTech and Spore used steganography & image files for sharing player-generated content.

I realize the original question isn't about steganography per say - my point is that using a format that is readily understandable by players & can be used outside your game may have benefits.

\$\endgroup\$
  • \$\begingroup\$ This is indeed an interesting gimmick, but usually the visible parts of the image isn't interpreted at all when importing it. The actual game state is usually hidden in the image metadata. PNG is quite useful for this purpose, because it allows to add an infinite number of ancillary chunks to an image which can carry any data you want. \$\endgroup\$ – Philipp May 12 '18 at 16:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.