Storing game 2d map data in Monkey

Monkey Forums/Monkey Programming/Storing game 2d map data in Monkey

dopeyrulz(Posted 2011) [#1]
If anyone has been following the compilation speed issues I'm having under GLFW (see here: http://www.monkeycoder.co.nz/Community/posts.php?topic=689), I got a 2d map which I've stored some array data for the map and collision tables. These are a straight flat array which I lookup using the (y * MapWidth) + x formula. The most concerning thing is the map is probably only 20-25% of the finished size.

I'm thinking it may be better to store this data somehow ie. string, compressed string, file? (can we read external files) and create the array on the fly.

Now, MingW does compile fine (as does HTML5 and XNA) but I would like to see what other methods are available. In the long run a multi-map game may require something other than large pre-stored in-code arrays so I'm throwing this open for discussion.

Currently this is how I'm storing the main tilemap:



dopeyrulz(Posted 2011) [#2]
Ah - hadn't seen the LoadString command (thought that was an internal function). This may help...

Any other suggestions??


therevills(Posted 2011) [#3]
At the moment, you can only really use LoadString or hardcoded arrays...


dopeyrulz(Posted 2011) [#4]
therevills,

Thanks for replying. Yeah certainly looks that way.


skid(Posted 2011) [#5]
Does changing Field to Global for _tileMap help the compiler issue?


dopeyrulz(Posted 2011) [#6]
Simon,

Thanks for the suggestion - unfortunately didn't make any difference. I stopped it after about 7-8 minutes. It's certainly a VS issue as it sits on Generating Code the whole time. If I rem out the 2 main arrays to :[0] instead it happens quicky.

Going to have a go at reading out of files tonight. Just need to create a read process in Monkey and update my Blitz3d map editor to write out some data. Probably a better method in the long run anyway.

Will report back my findings once complete.


JIM(Posted 2011) [#7]
If your IDs don't get past 255, you can just output them as bytes in a file, then you can leave your code almost intact, as you can access strings with the [] operator :)


AndyGFX(Posted 2011) [#8]
Make simple compression like this:
<map width>,<map height>,<value1>,<count1>,<value2>,<count2>, ... <valueN>,<countN>

I believe that this reduce your loading time too ;)


dopeyrulz(Posted 2011) [#9]
Guys, thanks for the suggestions. Andy, that was one method I was considering and Jim, will take a look at your suggestion also.


JIM(Posted 2011) [#10]
Mine's more of a hack. You might run into problems with 0 for example. I think it's considered an ending character. Not sure though.


Samah(Posted 2011) [#11]
Make simple compression like this:
<map width>,<map height>,<value1>,<count1>,<value2>,<count2>, ... <valueN>,<countN>

The problem with this is that unless your map contains a lot of repeated values, you're essentially doubling the size of your data. What I would suggest if you want to do this, is to use an escape code to enable run-length encoding.

http://en.wikipedia.org/wiki/Run-length_encoding

Say for example you have:
41 34 90 10 00 00 00 00 30

With a raw <value><count> you would have:
41 01 34 01 90 01 10 01 00 04 30 01

Which is obviously not what you want.

Let's assume your escape code is 255. You could then encode it like this:
41 34 90 10 255 00 04 30

Much better. :)


skid(Posted 2011) [#12]
Another workaround may be to store the data in a monkey string instead and parse it like you would the result of LoadString:

Global level1$="12,13,14,15,16,"+
"17,18,19"

Field _tileMap:=IntsFromString(level1)



dopeyrulz(Posted 2011) [#13]
Thanks guys. Have been working on re-factoring my mapping process so will also review these options when I get back to that point.

I can updte my level editor to just dump the code into a text file it should be pretty easy to test all these options out.


dopeyrulz(Posted 2011) [#14]
Just a quick update - have moved the maps into text files and used LoadString to load them up and then parse. Compilation time is back to fast on all compilers!

Now this is going well I can look at some of the suggestions above to get the maps compressed down.

Just for some info I finalised the tile map size which is:
160x187 (32x16 pix) = 29920 tiles!

The collision map is bigger again
320x187 (16x16 pix) = 59840 tiles!

Couple of other notes:
The maps are stored in 1d arrays.
The tile size is bigger to reduce the number of drawings on-screen (res 640x480).
The maps load very quickly and draw at great speed (20x26 tiles on-screen) - even as the map has got much bigger during development
Even in HTML5 the scrolling is quite smooth - go Monkey!


Dima(Posted 2011) [#15]
You could potentially reduce the file sizes by not saving empty or redundant data.

There are a few different approaches for saving tile maps. Normally the simplest way arranging everything is to match the actual layout of the level in the text file. So a 5x5 level data might look something like:

x000x - 0 are empty spaces, x are filled, Z is chilling
0x0x0
00Z00
0x0x0
x000x

Tile Maps usually suggest that there are more instances than reference tiles, in the above map there are 9 instances of x and 16 instances of 0. Even if you were to replace all 0's with blanks, it still takes memory space and is redundant.

Instead, I do something similar to this:

level.txt
...
...
"x",0,4,6,8,16,18,20,24
"Z",12


This simply states that I want tiles 'x' and 'Z' to be inserted into the following array indices, and to further reduce file size I treat my 2D map as 1D so there's no (x,y) position being stored, only an Int as an index of my 2D map in 1D view.

With this approach you can completely ignore saving empty spaces, because they will be empty by default when you init the 5x5 map. This is REALLY worth it when you work with big maps and large amounts of empty spaces. You only save what you need, and how much you need.

Further modifications can save more space, for example this map has consecutive tiles and can be encoded;

original 2D map (5x3)
xxxxx
xZZZx
xxxxx

same map but unfolded into 1D array
xxxxxxZZZxxxxxx

and this is how its stored in file:
"x",0:6,9:6 - similar as first example
"Z",6:3 - but with an addition of (optional) sequence parameter

First number is the index just like before, and second number following ':' is how many in a row to place. 0:6 means start at index 0 and place 6 'x' tiles consecutively, notice how 6 is larger than map width, but we're wrapping 2D in 1D so 6 carries over to the next row. Same thing for 9:6, start at index 9 and place 6 tiles. There is just 1 consecutive row of 'Z' tiles, and that should be self-explanatory by now :) And if it's a lone tile (not repeated) just omit the ":1" and leave only the index, the code can default it to 1.

Hope this helps.

Cheers,
Dima


dopeyrulz(Posted 2011) [#16]
Dima,

Thanks for the suggestions - quite interesting concepts! I've used a similar concept as your first suggestion (in 2D) though, but the 1D storing is certainly a great way to go. I have an overlay to provide some depth in certain areas - this would make this tilemap file tiny.

You appear to have a background in working with limited hardware and resources based on your recent postings (all very clever BTW). Welcome aboard!


Hima(Posted 2011) [#17]
Man, working for a mobile device is so much like time traveling!