Development of map system


The first step is to create a Grid Based system to emulate the Dungeon Keeper style, to begin - I wanted to use Godot's SurfaceTool. 

Previously, in past games - I've spent many hours using Godot's ArrayMesh to create maps, and felt like a change this time.

To absolutely no-ones surprise, my first attempt at using SurfaceTool failed miserably, generating no mesh at all (progress...), I took a break to clear my mind before scrapping my initial attempt completely. Back to basics, entirely.

After looking around the web, I found a suggestion to assist in my endeavors: "Random Momentania". This individual is a user who has created many tutorials - including for Godot. After reading over his examples of SurfaceTool, I was able to figure out where I was going wrong, and build a basic plane (pulling from my Grid system). It took a while to figure out the best winding method, and a little fun in MSPaint...


Iterating on that basic example of a cube that I managed to get running - I was further able to generate a basic small map (from the Grid) with walls (tile: 1), and a section in the middle of the grid that was ground (tile: 0). Alongside this, I discovered an interesting thing...

When using UVs with Surface Tool, meshes suddenly appear to become unmerged sets of quads (the quads you see are not merged together, they are all just floating in place). This might cause issues for NavMesh and/or alpha opacity later on, but the downside of not using UVs is that the mesh is sort of useless...

(Below you can see, the first iteration has no UV data - thus it is simply black, then when adding the UV data - the ground tile is using the orange colour from my material atlas, and the walls are using the yellow colour from the atlas).

Sticking with the use of UVs (so that I can make blocks use a texture atlas like Minecraft with its blocks), I then began cleaning up the winding, and moving to the next step: Digging into the walls of the mesh, updating the Grid, and propagating those changes to the mesh itself.

To obtain the mouse grid location, I called back to a previous game I've made and used a drop plane + Godot's raycast from camera methods, this works and has been used before. From there, when "clicking", a function is fired to set the tile at the mouse location to a unique tile number (corresponding with a colour on the texture atlas). When the Grid's tile is changed, it emits a signal that the mesh generator was connected to to delete the mesh, and rebuild it from the new grid data. This all worked awesome... until I increased the map side to 128 x 128, then I was getting 0.5s - 2s lag on each click, as it was deleting the 128x128 mesh and regenerating it from scratch each time.

To get around this issue, though, was a rather simple implementation (after a bit of trial and error), I decided to delve into the world of Godot Multi-threading for the first time. I created a chunk system - setting a chunk size of 16x16, dividing the map into chunks, and creating a mesh just for those segments - each chunk generates on its own thread, then after generating the mesh - hands it back to the main thread where the collider is generated. The idea is, when the grid is updated, it can emit the Grid Updated signal with the tile location that was updated, this can then be down converted into the Chunk that the tile in question exists in -> selecting that chunk, and forcing it to rebuild the mesh and collider only for that chunk. This saves rebuilding 128x128 cells every tile update on the main thread!

Playing with Threads? What could go wrong... everything! Every time I tried to run the game, it would immediately and silently crash. After making a few tweaks to the code - suddenly it would generate the mesh, but then throw "Memory Access Exception" errors, with illegal memory access attempts... scary stuff. Though, after digging through the documentation - I figured out what was causing these issues. You must avoid writing/resizing Arrays and Dictionaries inside a non-main thread! In light of this, I moved the "vertices, uvs, and indices" array generation outside of the Threaded function and back into the main thread. Upon next launch, the whole thing started working buttery smooth! Optimized, with no latency at all on each tile update and subsequent mesh chunk update...

You will notice there are a few holes in the mesh in the above animated GIF, this is the next thing that I will be adjusting, the reason is because the tiles I am updating are right on the border of 2 chunks, and since only the chunk that the tile is in is updated and rebuilt - the neighboring chunk doesn't realize it needs to render walls to fill those holes.

All in all, I've been enjoying working with these newish tools in Godot that I've not really touched before, and to realize that I have the basis of the game system already working and at such an optimized level is exhilarating!

Thanks for reading, stay tuned for more development updates :).

Get Crypt Underlord

Leave a comment

Log in with itch.io to leave a comment.