Making a Procedural Map Builder

In my current project, map is builded block by block. Map has 3 main blocks;
Uninteractable Water Blocks, which surrounds the map;
Normal blocks, which you can select/move on;
Interactable Water Blocks, which gives you a minigame to play when selected.

In game you only can move on adjacent tiles. Interactable Water B. is only can be interacted when adjacent to current block, but you can’t move on them; they just trigger a minigame.

Now, if a situation like this occurs, map is unplayable;


because I can’t move on two blocks at up. There is no connection between them.

I want to write a Procedural Map Generator for this game, but I didn’t wrote one, myself, before.
Can you point me in right direction for this? Also how would you approach this problem?

(Map grid is not 3+1x3+1 always, after Lv. 1 its lengths are choosen randomly.
You can’t interact blocks that are on diagonals.
Also Interc. WB’s must have a SpawnRate, because they are Bonus Blocks, which contains a mini-game.)

TY for taking time ^^ !

What’s the difference between interactable and non-interactable water? Is only the outer layer of water blocks non-interactable, and all other water is interactable?

I’m also not quite sure if i understand everything about your game. So i’m assuming the player starts on the dark grey block? What is the goal of the game? You said the map in the image is unplayable, because the top-most solid block cannot be reached, so i assume it’s either the goal to walk over every block, or reach the top most block, or reach some random block, which in the image happens to be one of the two top ones.

All of the above is kinda important for providing proper help for your problem.

Based on the information i have, i’d suggest to take a look at procedural maze algorithms. Possibly not exactly what you want, but it will quarantee that there is a path to every block. Then for example, after generating the maze, simply surround it by non-interactable water.
While we are talking about it…, what should a map even look like?
Another rather important piece of information for building a procedural generator for these maps :wink:

@Yoreki , Sorry didn’t noticed my information is too shallow. Let me explain my idea;
First of all, game is inspired by Minesweeper. As I said there is 3 main block types (for now),
-Non-interactable Water is just for aesthetic of map. It surrounds the grid.
-Interactable Water is a Bonus block. If you are standing on a block that is adjacent to Water, and you touch on it, you play a little fishing mini-game,4965191--483194--minigame.pngwhich gives you bonus points.
-Solid Blocks, have 3 types; empty ones, which gives you a little points for moving on them.
ones with trap, which obviously kills you,
ones with treasure, which gives you a bonus points.
This is a infinite high score game (for now, idea is still in development), and each time you complete a map, a new one gets builded, with lower chance of bonus tiles (Water,treasure), more trap blocks, and with a bigger grid. (3x3->8x5 etc.)
To complete a map, you must move and gain points on map in a time limit, but if you stay on a block for more than a few seconds, a meteor comes; to encourage you to move :). You can escape from it. Also you must gain more points than a randomly choosen lower limit.

In Minesweeper, there is numbers that tell you how many mines that are adjacent to that square. Similiarly, I’m currently building a logic map for this game, which gives you a great idea about what to do, if you solve it.

Yes, dark block shows current block (also have a floating animation, I didn’t draw a character, yet…).
First block is the first block that is non-water. Grid starts from (x:0,z:0) goes in +x+z direction (I’m not using y axis).

I don’t know if my explanations above gave you an idea about what a map look like, I will share a few playable maps screenshots with you: 4965191--483197--map1.png 4965191--483200--map2.png

Also, @Yoreki thank you for taking time to answer ^^ ! I wish you a beautiful day :slight_smile:

Ok, with the new information it’s a lot easier to understand what you want. The one thing that’s unclear to me now is why the map in your first image is unplayable. You managed that the game is basically about getting as many points as possible within some time limit (after which i assume you get to the next map). So not being able to reach some blocks could potentially be decremental to the highscore, but wouldnt make a map unplayable, would it? Then again, if we want to create random maps, highscore wont be consistent. Unless, of course, that’s one of your requirements. We could potentially design some system that guarantees that each level, while featuring a random layout, has a fixed amount of (connected) blocks. Is that a requirement?

So while there are still some potentially important questions above, let me suggest some possible approached to your problem of generating these maps procedurally.

  1. Noise
    There are some coherent noise functions that often get used in video game development for a variety of things. One of them is Perlin Noise. For each coordinate of your board you could sample a 2D Perlin Noise function with your coordinates as input. The function would return a value between 0.0 and 1.0 that is coherent with the values around it, but still pseudo random. To give you an idea how that looks like, visualizing these values as color would result in a texture like this:

    As you probably can imagine, if you scaled this accordingly and placed blocks where the noise value is above some threshhold (ie pixels appear to be white), you’d get a similar representation for your map. To generate different maps you can simply adjust the offset and scale of the noise (plus you can overlay different noise functions too).
    In case you want to experiment with this, it is worth mentioning that perlin noise will return the same value for all even integers (0, 1, 2, …), so you will have to scale the input values by some (“noise scale”) value. For most applications, a value between 0.03 - 0.15 works well.
    Also, it is not guaranteed that all blocks will be connected. Using noise may lead to the creation of “islands” of blocks. However, other than that it will probably result in the most well looking levels being generated, and if you need all blocks to be connected, you can use another algorithm afterwards to guarantee that they are all connected!

  2. Noise, but the other way around
    Similar to what i wrote in 1), you could do it the other way around. Start with a map that is all blocks, and use noise to punch holes in it (water blocks). Depending on the scale of the noise, this would result in lakes, rivers, or scattered single water blocks.

  3. Maze
    As i mentioned previously, procedural maze algorithms are a thing. They will guarantee that the entire available space on the map is used up with either water or solid blocks, while also guranteeing that all solid blocks are getting connected. However, this would result in all solid blocks being adjacent to water, so you would have to either adjust the algorithm, or add a second step afterwards as well. Maze generation algorithm - Wikipedia

  4. Semi-random placement
    You could randomly place the blocks in a way that gurantees that they are all connected. It also gives you perfect control over the amount of blocks you want to place in a level, but has other draw backs.
    First you have an empty matrix. You randomly or manually pick th starting location, and insert that location in a list of occupiecLocations. Now find all adjacent empty blocks and put those in another possibleNewLocations list.
    So for every new block you want to place:

  • Take a random location from possibleNewLocations
  • Spawn a block there, and save its location in occupiedLocations
  • Find all adjacent blocks (beware of board borders!) around the newly placed block
  • Insert all of the adjacent blocks that are not in occupiedLocations, into possibleNewLocations
  • Repeat

This way every new block is spawned adjacent to another block, guaranteeing that all blocks are reachable. It also gives you perfect control over the amount of blocks you want to place per level. One drawback would be, that this would most likely result in blocks getting clumped together. To prevent this, you could give all values in possibleNewLocations a probability, that is based on theid distance from the spawn. That way you could make it more likely for blocks to get picked, the further away from the spawn they are. However, this may result in many “bridge-like” maps. Another approach would be to decrease the probability based on the amounts of blocks in the area around it. As you can see, this approach has a lot of benefits, but can also get a bit finnicky to get to do what you want it to.

1 Like

If levels win requirements are pre-defined, there is a chance that map is unplayable if it is generated independent from games logical rules.

No, fixed block count and consistent high score aren’t requirements. And since there are two bonus block types, there is more than one factor that affects high score.

While researching, my ideas changed. Now, your post really helped me to shape my idea.

I found a way to eliminate/replace unreachable solid blocks; but after reading a few maze generation algorithms and seeing some results, I decided it will be better to give level-design more importance. I was thinking about using some pre-generated black&white maps to decide how level would look; but after reading your post, your idea seemed brilliant!

I know what is Perlin Noise, I didn’t know how can it be used on my game. Now you give ma a new idea.
I will use Perlin Noise from reverse (your second approach) to build my small-medium maps, and use close to 1 values for larger maps (your first approach), this will help me to create not-boring-looking maps on large scale.

About 4th approach; I want the amounts of block to control logic of level (& logic map), so I don’t want to have control over block count for now.

@Yoreki Thank you so much for your help.

1 Like

@Yoreki Hello again!
After researching Perlin Noise a little, I implemented it to my MapBuilder. But I was looking for randomness to make every map unique. I tried a few things to achieve this, but I didn’t get the uniqueness I want. (Of course, map can look similiar, especially smaller maps at earlier stages of the game, but with my current implementation it looks like algorithm is just changing a little percent of the map each time - on same scaled maps - and they looks so similiar.)

I tried;
(input + seed) * (perlinNoiseScale + (perlinNoiseScale / seed) and feeded it in Mathf.PerlinNoise; but I get really weird results. I choose seed via Random.Range(0, 1000000000) //Also some other values, negative, positive..., somehow calculations were always giving some big numbers, in calculator they’re okay, so I changed this approach.

After that,

var bias = Random.Range(0.03f, 0.15f);
                noiseMap[indexX, indexZ] += (Random.Range(1f, 100f) <= 50f) ? (bias) : (-bias);

I added some bias to my noiseMap values, and distrubuted it randomly and fed Mathf.PerlinNoise via biased values; but still maps wasn’t that unique. (I shared 3 maps made in 30x30 dimensions.)

Maybe I’m missing something, but; how can I build completely unique maps using Perlin Noise? Maybe try another method? How would you use one of the methods you suggested to build unique maps each time Player plays my game?



Since you are dealing with literal cubes a more long term option that might be better suited to your gaming would be to have a look at the marching cubes algorithm this could maybe help you create even bigger procedurally generated levels.

Marching cubes is an algorithm used to polygonise a scalar field, for example MRI scans. While it can be used in conjunction with noise to visualize procedural worlds, and i’ve actually done that, it’s not related to OPs map generator. Unless, of course, if OP wants to get away from the blocky look. Despite the name “marching cubes”, the algorithm does not result in cube-like shapes. Rather, the “cubes” part references to a visualization of the algorithm at work, where a “cube marches” through the data, deciding which polygonal shape to place at the given position, based on the scalar data in the 8 “vertices” of the cube.
Marching Cubes Visualization

There are some thing to keep in mind. You can adjust the scale. You can generate values for an offset. And you can mix different noise functions to get a more interresting result.
Adjusting the scale basically means you’ll just zoom in or out of the noise, so you could for example “zoom in” more in lower levels, to generate more land, and then zoom out for later levels to generate more water. Or the other way around.
Starting the generation at an offset, is what generally results in different terrain. When you generate a 10x10 map and start at 0, then the next time you generate this map size, the map will look the same. An offset is like a seed, determining where to start. So you should generate an offsetX and offsetY, and start at [offsetX, offsetY], with the end point being at [offsetX+10, offsetY+10].
Mixing different noise functions can result in interresting patterns, which is often used for 3D terrain generation, since a single noise function generally does not look very interresting for most applications. I dont think this makes a huge difference for now, but maybe have a look at other noise functions like Voronoi, Worley or Blue noise.

In a 3D world, different noise functions would be different “Biomes”, the offset for where you start the map would be your “Seed”, and the scale would increase or decrease the detail level of the terrain (even tho, depending on the sample resolution, obviously a lower level of detail is better, since otherwise all the detail would vanish into below-sample-sized spaces).

That said, there seems to be something wrong with the way you generate your maps, since it always results in this kind of hole to the right. If what you wrote is all you put into the noise function, then you are forgetting about the actual coordinates. The value for each cell can be described as follows (see it as pseudo code example):

Vector2 offset = new Vector2(Random, Random); // chose value from 0-10mil or something each. PER MAP! Not per cell!
float noiseScale = 0.03f; // our noise scale. See what works best. PER MAP! Possibly change between maps if wanted, not necessary tho

for each cell: // in your grid, so it's actually more like a nested-for loop over all x's and y's
    Vector2 cellPosition = ... ; // whatever cell this is. From 0,0 to 0,1, .. to 10,10 for a 10x10 grid
    Vector2 input = (cellPosition+offset) * noiseScale; // adding cell position to offset results in a unique value per map, based on the offset ("seed"). the scale is applies since even values always result in 0.5f, and also to regulate the "zoom"
    float noiseVal = Mathf.PerlinNoise(input.x, input.y); // doing this for each cell would result in a image similar to the above greyscale image, if we were to visualize the output

And i’m sorry, since the comments got pretty long and this makes it hard to read…

2 Likes

Thanks for the explanation I didn’t know that, the algorithm examples I’ve seen gave me the impression everything was made up of cubes and it seemed it would be simpler to implement a map design of some sort if your game was made up of cubes, I guess my understand of it all is still very basic.

I thought it was something akin to grid or hexagon code where you had everything important within the shapes.

1 Like

@Lethn thank you for suggestion; I want to develop this project into something different, especially different maps made of different shapes, more block types, maybe blocks will be something different than cube. But for now, since I didn’t completed games logical part yet, I want it to be simple and blocky :). I will research your suggestion, I heard marching cubes but didn’t know it was a algorithm used for procedural generation.

@Yoreki , thank you again for responding ^.^ ! I used your offset solution, but as you can see in my post (I called it “seed”), I used offset in a wrong way. Now I spotted my problem, thanks to you. Since I’m using x-z axises, 3D Noise methods will not make much difference; but I will take a look into other Noise methods.

About Marching Blocks, as I stated before, I want to develop more complex worlds; I will work on this algorithm a little. Maybe I can make levels like hearth shape, a zero or etc. with this?

Again TY for taking time!

You actually only need marching squares as you dont care about 3d for this type of map. There is a tutorial here on unity learn that goes over the algorithm and sets you up with a great map generator that you can then edit to give the shapes you want.

Your welcome and good luck :slight_smile:

1 Like

Thanks to you! After trying a few Unity tutorials, I think I stopped watching them, didn’t noticed this one :P.

1 Like

Once you have finished that tutorial you can easily modify it to generate the shapes you want instead of a “cave” shape, but the process is the same - it generates a 2d map of where the squares should go based on some algorithm.