Hello there đ I am currently working on a small project and needed to experiment with different map sizes and shapes. I took this opportunity to learn more about how maps can be procedurally generated in 3D.

** In this blog post I will show you how to procedurally create maps in Godot using Grid Maps. **

I also felt like I struggled a bit with creating and optimizing the code and I took this as a perfect opportunity to give back to the community :)

**đGet the latest version of the code here**

# Prerequisites

For this tutorial we will be using aÂ 3D modelÂ of a hexagon that Iâve borrowed fromÂ Jmbivâs tutorial.

Alternatively, you can also scour the web for other 3D models and resize them toÂ **1mm height**Â andÂ **~1.74mm width**.

As long as you donât want to sell your game and donât want to build the 3D models yourself, I suggest also looking overÂ MagHex Tiles for GloomhavenÂ which you can download and resize for your game.

# Setting up your scene

In this part you can follow my steps from the gifs in order to setup you scene with everything you need and then we can go over the nitty-gritty of the code.

If for some God forbidden reason the website doesnât load the gifs for you, ping me with your browser type in the comments and follow theÂ gifs posted on the repo.

Note - You will see in the gifs that the first key I press is F7, which I use for starting the recordings. You will not need to press F7 when tracing my steps.

## Step 1 - The Main Node

We will need to create a main node to which we will attach the other components and which will be displayed when running the game.

## Step 2 - The Main Camera

You see that nice blue horizon line in the background?

If we run the game as it is, we wonât be able to see it without a camera.

## Step 3 - The Mesh Library

In this approach of procedurally generating maps, we will be using GridMaps.

In order to take full advantage of them, we will transform our 3D object into a Mesh Library, such that we can later import it inside the GridMap.

## Step 4 - The GridMap

We now create the main piece of our puzzle, the GridMap.

You will see me typing in some numbers for theÂ **cell_size**. I will go more into details about those numbers when explaining the code. All you have to know now is this specific 3D object (now Hex Mesh) that we are using, we have to put in those values for it to perfectly fit between its brothers and sisters.

## Step 5 - Adding The Script

Now you just copy-paste the script, and thatâs itâŚ project done. Now you can add Godot game developer in your CV.

OrâŚ if you really want you can also follow the next chapters in order to understand how the code works.

# Understanding the code

The first draft For the first iteration of the code, all we want to be able to do is to create a rectangle given the number of rows and columns.

So letâs define the variables that we needâŚ

```
extends GridMap
# for now we hardcode the height of the 3D mesh
const TILE_HEIGHT := 1
# one mesh, one color
var num_colors := 1
# we expose the number of rows and columns
export var hex_rows := 7
export var hex_cols := 5
```

We will now use GodotâsÂ **_ready()**Â function to update the values ofÂ **cell_size**Â dynamically.

```
func _ready():
# in 3D the z component corresponds to the height of the mesh
cell_size.z = TILE_HEIGHT / 2.0
# we use the cosine function to find half of the hexagon width
# and stepify to round the result
cell_size.x = stepify(TILE_HEIGHT * cos(deg2rad(30)), 0.01)
_generate_square_grid()
```

Iâll try not to deviate too much and go into the math and why we use the cosine function here. But if youâre curios (which is something admirable) you can look at this explanatoryÂ YouTube video.

Now letâs actually generate the square mapâŚ

```
func _generate_square_grid():
for y in range(hex_rows):
for x in range(hex_cols):
# we shift the cell twice horizontally and once more if the row is even
x = x * 2 + y % 2
# we set the cell of the grid at the position (x, 0, y)
# with value 0 (our first mesh)
set_cell_item(x, 0, y, 0)
```

In the end, you should have a result similar to the one in the image below.

# Centering map - Experimentation

So a first approach to centering may be to move all cells to the right by half the width of the rectangle.

So letâs implement it and see if it worksâŚ

```
func _generate_square_grid():
# the shift should be equal to half of the length of the rectangle
# we don't divide by 2 because for every cell we need to multiply cell_size.x by 2
var x_shift = hex_cols * cell_size.x
for y in range(hex_rows):
for x in range(hex_cols):
# we now shift each element to the left
x = x * 2 + y % 2 - x_shift
set_cell_item(x, 0, y, 0)
```

Well that doesnât look quite right. Letâs try printing out theÂ *x position*Â of each cells in a row to see whatâs wrong.

```
# This logic is for a rectangle with 5 columns
X_shift is: 4.35
X is: 0 X-X_shift is: -4.35
X is: 1 X-X_shift is: -2.35
X is: 2 X-X_shift is: -0.35
X is: 3 X-X_shift is: 1.65
X is: 4 X-X_shift is: 3.65
```

It seems like the pattern may be something like even numbers from -4 to 4 with a 0.35 shift. But something breaks when we subtract the shift from 3.

# âď¸ What do you say about a small competition?

Try thinking of a way to solve the problem and after you come up with a solution, you can compare your solution with mine.

Iâll add some empty space for you not to get any spoilers.

Centering map - My solution So ideally what we want is to replace our range fromÂ **[0 to hex_cols]**Â to something likeÂ **[-hex_cols/2 to hex_cols/2]**.

Unfortunately at the time of me writing this blogpost Godot does not support negative ranges, so the only solution is to create our own range.

```
func _get_zero_centered_range(n: int):
var array = []
var shift = (n-1) / 2.0
# if n is equal to 0 we just have a centered element
if not shift:
return [shift]
# else we create the normalized range
for x in range(n):
array.append((x - shift)/shift)
return array
```

We then just have to integrate the zero centered range in our previous code.

```
func _generate_square_grid():
var x_shift = hex_cols * cell_size.x
for y in range(hex_rows):
# we create a variable to store our custom range
var zc_range = _get_zero_centered_range(hex_cols)
for x in zc_range:
# we shift the elements with half the rectangle width
x = x * x_shift + y % 2 set_cell_item(x, 0, y, 0)
```

Now what the map will look like would be something like this.

YupâŚ that looks a bit better but it seems like something is still out of place.

# Removing extra cells

It seems that on even rows the rectangle is a little bit longer. Nothing a fewÂ *if statements*Â canât solve.

```
func _generate_square_grid():
var x_shift = hex_cols * cell_size.x
for y in range(hex_rows):
var zc_range = _get_zero_centered_range(hex_cols)
# if the row is even, we remove the last cell from the range
if y % 2:
zc_range.pop_back()
for x in zc_range:
x = x * x_shift + y % 2
set_cell_item(x, 0, y, y % num_colors)
```

That looks mutch better, but how did we get those new colors?

Must have been a bug, who knowsâŚ

# Future investigations

Generating hexagonal maps should also be something to look into.

The starter code should be enough for you to wrap your head around how to generate the hex map, but if you struggle with it you can ping me in the comments and Iâll create a tutorial for it.

**đGet the latest version of the code here**

# Conclusions

In todayâs post we looked over:

how to create a scene and mesh library how to use grid map together with the mesh library how to procedurally populate the map with hexagon meshes If there are any questions leave them in the comments and Iâll try to answer them as soon as I can.

Hope you enjoyed the blogpost :)

Peace đ

# References

Jmbiv - 3D Hexcell Square Map -Â YouTube link

Gingerageous Games - 2D Squarecell Hex Map -Â YouTube link

Brian McLogan - Find missing length using cosine function -Â YouTube link