Procedural Map Generation

Hi! For this LudumDare we decided to go with procedurally generating the map each time the level is loaded. This is something that always scared me as a programmer. Game jams have pretty strict time schedule and I have experience of spending too much time implementing wacky ideas that seemed easy on paper but took tremendous of time and didn't even end up being fun to play. Luckily the map generation turned out to be much easier than I anticipated. If you want to know how I managed to do it, join me in the explanation post.
Intro
With "depths" as the theme of this Ludum Dare I quickly though about game where digging is the main mechanic. Unity have pretty nice tile-maps components, modifying tiles in runtime is trivial, and with RuleTile extra package from Unity placing tiles that looks correctly depending on the neighbours is extremely easy. Plus the tile-map automatically re-renders neighbouring tiles when something changes around them.
The tiles themselves are rather simple but you can notice that border around them changes when I add/remove/modify the neighbours.
Abstract
When there's digging I didn't have to bother generating the map that have connections between tunnels and caves - the goal for the player is to make them himself. To make the traversal through destructible map easier the player begins with things like double-jumping, wall climbing and grapple-hook.

OK, let's get to the map generation! The game was made in Unity, one of the best features of that engine is how elastic the UnityEditor itself is, and how much can be done inside it. I wanted the map generation to be possible in the editor to test there if good looking maps are generated after tweaking the params without needs to restart the game every time.

I won't get into the details what each param does, the most important is the button at the bottom that'll generate a new map inside the editor. That helped to quickly find and debug issues with map generation and make it usable in the runtime.
The basics - dirt tiles
The basic thing is obviously generating a map with specified tile size, and generate an indestructible tiles around it. It's a game jam, so there's no infinite map generation as the player reaches map boundaries. The map size is fixed and that works just fine.
With tile size 30x30 here's the map that shows dirt tiles plus the boundary tiles all around.
Adding flavor - rock tiles
There's a second type of diggable block - the rock that takes slightly longer to dig. I wanted to put patches of it on top of the dirt. I knew that top-down games have their own smart ways to generate fantastic landscapes, mountains and different biomes and I wanted to generate rock that way but obviously implement it as simply as possible. After some googling I found a nice article online titled A Guide to Procedural Generation. It described how to achieve exactly that and so with slight modifications I took their NoiseGenerator.Generate() implementation and used that for just the rocks.

Make some space
Now the map needed some space - even though the game is about digging it would quickly become boring if the whole map was filled with tiles (and only two kinds of diggable ones). This type of holes doesn't really need anything inside them - they work simply as a break from digging and as occasional passages between caves (but that's totally random so they might also lead you nowhere). My MapGenerator accepts an array of HolesConfig. The hole can be either a tunnel or a well. I specify how many of them I want and how big they potentially can be, their width and height are defined as range. When I apply them I simply remove the tiles at the space they occupy.

Add pre-made segments
The map have tiles to dig and space to run around. But it lacks decorations, environmental hazard (spikes) and enemies. Placing them completely random in maps with random tunnels that look like ones above was a bit too risky. Instead we introduced another type of caves - hard-crafted small segments that are decorated, contains traps, hp pickup, looks nice and will be placed on top of everything on the map.
The caves are saved as a prefab object. When MapGenerator grabs such cave it checks its boundary and randomly places it on map in a way that it won't intersect with other caves. Then it copies each tile from the cave and applies it on its own tile-map and places other GameObjects (enemies, extra hp). You can notice weird red grid inside the cave - this is special type of tile that defines which tile should be removed from the map. This is because caves can have different shape than just the rectangle, notice the shape of the cave above. I wanted to have an easy way to define which tile should be removed when cave is placed on map and which should be left untouched.
Red rectangles in the gif shows the boundary of the caves (the boundaries are in fact rectangles but that's simply because that made calculations simpler). I added that inside the Editor to quickly see that indeed caves don't intersect with one another.
Final touch
There you have it! The only thing left is placing minerals randomly on the map the (the game objective is to collect them btw). Oh, there's also starting cave that needs to be placed somewhere on the top.
The big pipe is your starting area, and those shiny thingies are minerals that you're looking for in the game. Don't worry about the map size in the gif, I configured it specifically for this blog post, in the game itself it's much bigger :)
The end
That's the map generation. It took me about half of Sunday to implement that behaviour (plus some extra time on Monday for polishing and tweaking). Being able to do so much in the editor alone made the process much quicker - If you're Unity developer I highly recommend playing around with expanding the Editor, it can make development much easier.
If you've reached the end of this post write "Dig In, Gus!" in the comment. And hey, if you like the idea of our game or graphics shown in the gifs grabbed your attention I would appreciate if you would try our entry for this Ludum Dare: https://ldjam.com/events/ludum-dare/57/dig-in-gus
Happy digging!