Minimap and Map Chunking in Godot | Devlog #7, Final Form


Hello!

Today's devlog is about a minimap and tilemap chunking I've implemented in Godot. This time, the devlog is way more technical, as I did just one small thing, but it was an interesting technical challenge. 

So the challenges were:

  • The game works perfectly if I have a 60x60 board, but when it gets much bigger, any change in the tilemap takes too much time to process. 128x128 was the limit, and for 1024x1024 the game wouldn't even load. Honestly, though - 256x256 is the maximum map I can imagine playable (barely - 128x128 is good practical limit), I wanted to make it work for even crazy tile-map size :)
  • And I also need a minimap, which in a sense doubles the map, and shows even more entities (even if simpler) at a time.

So first, minimap.

My first idea was to make it like I did for a jam - drawing primitives, but since it is CPU-based, and the area I wanted to draw is ~320x240 pixels, with 3 layers (biomes, features, units), I thought that it might make the game stutter. 

The next idea was multimeshes. It was perfect when minimap consisted of ~2000 tiles (each tile 12x9px), but when it got to ~8000 tiles (6x5 pixels) - it became too much. Or rather - it was ok, but it became too much after I added tilemap chanking on camera movement... It was cool to learn multimeshes (really liked them! way easier than they seem - although tutorials are a bit too barren in godot docs), but that was too much... I think I might have made it work if I made a good way to keep when to redraw all meshes and when to alter some (by index) - but I decided to try something else. So I kept them for unit flashing only.

The next idea was - making an image for the tilemap, and updating it when the map changes. This seemed to go perfectly! It takes more time when the game starts (as it takes time to create an image from scratch), but panning the image with camera movement was almost seamless, smooth, and had almost zero impact on the game's performance. The problem happened when I tried working with a 1024x1024 map - adding a new pixel to it was a bit too heavy, took way more than a few frames... The issue is that a whole 200000x150000 px image has to be loaded into the GPU every time something changes on the map. But with even a 512x512 (let alone 512x512) map, it works with no lag! But still, to mark the problem as solved, I need to add chunking here as well - probably split the map into images of 128x128 size, and edit only affected images, not all of them.

And the map chanking! 

In short, it works like this:

  • In a static state, the game keeps two areas in mind: one is a 25x25 square (a bit more than fits the screen), and another is a 41x41 square. This (and other) square is technically a thombus - since my grid is isometric, the square that fits the screen is a rhombus in isometric coordinates, so it has about 2x amount of tiles. So it's around 1300 and 3200 tiles, which is a lot, but can be set in a few frames.
  • The smaller square is drawn in full biome, decoration and features (9 sub-tiles), layers for yield and shield icons, etc. ~20 elements in total. The other 3200 - only biomes are drawn.
  • Before the camera moves, it creates an area of 21x21 square (that fits the screen on max zoom-out). So within the game screen, it's ~800 tiles.
  • The camera waits one frame for those 800 tiles to draw (usually most of them are already drawn, since the camera usually moves not too far away from the previous square), and only then does the camera start moving.
  • On camera move, each time it crosses a tile border (goes to a neighbouring tile) - it updates the 25x25 and 41x41 squares, and queues to draw the new tiles that are not yet drawn. There are 2 queues - one for biomes, one for full decoration.
  • Every frame, in "process," the game checks the queue and draws. It has a counter of 1000, and each biome drawing takes 1 counter, each tile removal takes 10, and each decoration takes 20. So when there are biomes in a radius of 20 tiles that are not drawn yet, they are drawn first. Then, if the counter is not over 1000 yet, it removes the tiles that are no longer in that square. Finally, only if biomes are placed and old tiles are removed, tiles get decorated.
  • This works surprisingly fast! And with this system - even the 1024x1024 tile map is a breeze - I can pan around with zero lag, and every game action runs smoothly. And even when I move the camera quickly from one side of the map to another, the camera fails to load all decorations, but it loads all biomes, which is good enough when you cross the whole screen in like a quarter of a second.

So that's all I have to share! Many technical details - probably too much for those who are not into it, and not enough for those who are :D I might end up doing a tutorial about map batching and minimaps, if I have time and feel like it :)

And another big new - the reason I'm making this devlog so early in the week - tomorrow GMTK game jam starts, and I'm in! I'm so eager to get into a jam after half a year, and see how it works! This time I joined the team rather than assembled it myself - last GMTK they got #67 out of ~8000, which is crazy good and I'm happy to join them this time and see where it goes :)

It's only 4 days though, so next monday I'm back on Final Form :) But I will share GMTK results next devlog too!

Comments

Log in with itch.io to leave a comment.

Being able to do a gigantic map can be a nice thing for a free/creative mode for the more casual players (or moods). :)

In the video, when you went from the edge to the center of the map, with the game being unable to render all the decorations in the process, for me it was pretty decent as it gave that blurry feeling that came at high speed. I couldn't see the decorations clearly, but I could see some flashes here and there. hahaha Maybe, at far distances, trying to load just a few random tiles might do the trick.

Good luck in the GMTK jam! :D

Also... A HUNDRED THOUSAND LINES?! :surprised_pikachu:

(+1)

Thank you! :)

For the long-distance map-travel I think of another trick - but not implemented yet - draw a screen-width "line" between current and target location, and draw all tiles within that line before the camera moves. And if it is so far that even that is too much - then I just move camera with fade-out/fade-in animations :)

I really want to do GWJ, so far it's my favourite, and I really love the community. But timing doesn't align, and it takes so much time! :) Will probably go for it again when the final form demo is ready :)

100k is just an estimate :D But I think it's close to reality, given that I use data-centric approach and store most of the data (like runes descriptions and tranformation atlas coordinates) in tons of dictionaries :) I love dictionaries :)

It's also been a while since I participated in GWJ because of time, I understand :/

Technically, you are kind making the “line”, but segment by segment. hahaha But if you can make it work (I don't doubt it c:), it would be cool. A fade-out/fade-in would also be nice, like a little teleportation. :D

I like dictionaries too, but not so much it seems hahahaha