# Procedural 2D map generation

## Introduction

In this article, I will show you how to create simple 2-dimensional map based on Simplex Noise. We are going to write a map generator in Python using The Python Arcade as a game engine and OpenSimplex library as a noise generator. Let's go!

### Prerequisites

• Basic knowledge about game engines.

## What is this noise about?

I don't want to make a math science here. Let's keep things simple here.

We want our terrain:

• to make it looks like a real terrain
• to make it repetitive while using same seed
• to make it unique while using different seeds

Basic concept looks like this: there are known coordinates like X and Y and random constant called seed. We want to obtain Z coordinate (height) for each (X, Y) point. The magic is that with same seed there will be always same result. In my example I generate 2D map, but there is no obstacles to make it 3D. I created ten 16x16 sprites, each for different representation of Z coordinate. Z is going to have values from -1.0 to 1.0. Everything below 0.1 is going to be ocean, then I made some greenery, rocks and snow on top of mountains.

Preview: ### Code review

Let me explain best parts:

```import arcade
from opensimplex import OpenSimplex
import uuid
```

Why reinvent the wheel? We are going to use opensimplex library which gives freedom in creation of Simplex noise. In this example I use uuid to generate a truly random grain. Let's move on to main methods:

```def generate_seed(self):
return (uuid.uuid1().int >> 64)

def generate_world(self, x, y, seed):
tmp = OpenSimplex(seed)
z = tmp.noise2d(x=x, y=y)
return z
```

Random seed generation is optional. In this example we are going to view maps generated by different seeds.

```def setup(self):

# Set the background color
# Sprite lists
self.seed = self.generate_seed()

def update(self, delta_time):
self.seed = self.generate_seed()
for x in range(self.x_start, self.x_end + 8, 8):
for y in range(self.y_start, self.y_end + 8, 8):
z = self.generate_world(x=x * 0.01, y=y * 0.01, seed=self.seed)
if z >= 0.9:
elif z >= 0.8:
elif z >= 0.7:
elif z >= 0.6:
elif z >= 0.5:
elif z >= 0.4:
elif z >= 0.3:
elif z >= 0.2:
elif z >= 0.1:
else:
tile.center_x = x
tile.center_y = y
self.tiles_list.append(tile)

def on_draw(self):
self.tiles_list.draw()
```

In each update:

1. arcade.SpriteList() with 16x16 sprites is cleared
2. seed is randomly generated
3. for each X and Y on the screen Z dimension is calculated
4. depending on Z (height), sprite (water/ grass/rock/snow) is selected 