Chunking tilemaps

i’m making a game what includes a top-down word that the player can walk around in. naturally, this necessitates a decent-sized map to give the player room to explore a bit if they so desire. when testing it became clear that 1 singular large tilemap would not work, as a relatively small map was already noticeably lowering performance from the engine cap of 1000 to 500 frames. so of course, the common industry workaround to that is to split the world into chunks and load/unload them as needed.

my question would be how does one do that while not making editing the tilemap too difficult (for example, creating several tilemap objects, as they must be edited and joined separately) and while not creating discrete loading screens, as that would hinder the flow of the game.
what are some of the different methods to solve this as well as their drawbacks?
i’ve tried making a second tilemap for the use as the display while the primary remains hidden with the data, but the engine is spitting out a lot of errors when i set tiles on coordinates that are 0 (SetGridShapeHull: unable to set hull [x] for shape [y])

1 Like

Hi @CrazyAmphibian !

Personally, if the size of the map is beg enough, I’d author the map as a single .tilemap.
Then I’d write a python script (or other scripting language), to split that big tile map into smaller ones (our file formats are protobuf text!), and also create a collection (e.g. bigmap.collection) with collection proxies in them. These scripts can be run before a build starts, using our .editor_script.

Each collection proxy points to a collection (e.g. piece00x12.collection) and it in turn points to the smaller tilemap (e.g. piece00x12.tilemap).

The bigmap.collection also will point to a script that can receive messages that deal with loading unloading the map pieces.

There are multiple ways of doing this, but this is the main idea.

By using collection proxies (as opposed to collection factories), I can separate the resource loading, so that the tilemaps (and possibly other resources, such as sounds/music) can be loaded/unloaded as the player moves along.

Another thing to look out for in a very large map is floating point precision, which may make things look strange/buggy when the camera is far from the origin (0,0).
A common way to deal with that is to keep the map pieces and the player close to origin, by moving them accordingly. An example of this is an infinite runner game: The player doesn’t move, but the game world does!

4 Likes

i’ve never used collection proxies (or editor scripts (or collection factories)) before, so if push comes to shove i suppose it’ll be a learning experience for sure.

in the meantime i did figure out an admittedly hack-y solution that does appear to work with, after a long time considering how to optimize it, not too heavy of a performance impact (still getting 900+ frame average while moving). it involves creating sprites for each tile and creating/deleting them as needed (though that did require boosting the GO and sprite limit a not insignificant amount)

a somewhat related concern i have about big tilemaps: right now i can feel the editor freeze up for a bit when drawing new tiles on the tilemap, and i suspect it will get worse as the size increases. any solutions for that?

1 Like

How big is the tilemap you are editing? For really large tilemaps maybe Tiled is a better tool? It experts directly to Defold.

right now it’s roughly around 300x200, though this is definitely subject to increase.

+1 for Tiled. It actually supports infinite tile maps.

On the Defold side I keep track of the player’s position, and when he reaches a boundary area of one chunk I load the next chunk. I do it with factories though, not proxies.

3 Likes

300x200 is not very large. I’m surprised that it is slow to edit at that size. Do you have a very large tilesource?

tiles are 96x96, 768x768 tilemap as of now.

tiled doesn’t seem to want to open defold .tilemap files

Correct, Tiled can export to Defold format.

But what size was the tile source? How many cells does it contain? :slight_smile:

sorry, 768x768 tilesource, not tilemap

1 Like

This is not a significant performance difference, I hope you test with a large map before spending a lot of time trying to optimize it. It may be a problem, but you won’t really know until you test it.

You should look at dt instead of FPS for measuring performance. 1000 FPS is 1 millisecond per frame (probably the minimum sleep time the engine uses to allow your computer to do other things). 500 FPS is only 2ms. On my computer, with any game engine, just having a blank window that’s maximized instead of half-sized can cause that difference. Compare this to 120 FPS which is 8.3ms, and 60 FPS which is 16.6ms - also halving the FPS, but 8 times the difference compared to that between 1000-500 FPS.

4 Likes

it is a significant performance decrease because the map is not that big.
the rendering time scales with tile count, and when i was testing how much it did that, i made a map that was *maybe* 6x larger, and that shot the framerate down into the 70s.
and this is before i’ve added any sort of complex game logic to the game, which will take further time away
better to optimize now than redo the code at release, methinks.
and it’s always better to have a better running game. it means that people who want to can run the game and unnecessarily high frames and believe it’s more responsive, and more importantly, it means that people on low-end systems can play at a decent framerate. people on laptops benefit most from this, as it means less battery is spent running the game.

1 Like

Well there you go. That’s all I was suggesting. :+1:

1 Like