简体   繁体   中英

2D noise generation in python

I created a program that generates random terrain and then displays it, using pygame. But my terrain generation is random, and thus very bad and i started to look up for noise. The noise package doesn't work for me it gives this error:

Command "c:\users\intel\appdata\local\programs\python\python36-32\python.exe -u -c "import setuptool
s, tokenize;__file__='C:\\Users\\Intel\\AppData\\Local\\Temp\\pip-build-vepf8y8v\\noise\\setup.py';f
=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compil
e(code, __file__, 'exec'))" install --record C:\Users\Intel\AppData\Local\Temp\pip-yim68ua0-record\i
nstall-record.txt --single-version-externally-managed --compile" failed with error code 1 in C:\User
s\Intel\AppData\Local\Temp\pip-build-vepf8y8v\noise\

And plus i totally don't understand how to do that. Let's say i want to generate something like this:

000000021111111200000000000000000000000000000000000021200000000000000000000000000000000000
000022211111111120000000000000000000000000000000000211120000000000000000000000000000000000
000211111111111112000000000000000000000000000000000022220000000000000000000000000000000000
000021111111111120000000000000000000000000000000000000000000000000000000000000000000000000

The 0s represent grass, 1s represent water and 2s represent sand. The sand must be next to end of the water, and the water needs to have some watery shape.

For me, terrain generation is a multi-step process.

( 1 ) Start out with primitive shapes like domes, which can be generated procedurally. Alternatively, You can also experiment with Voronoi plates and have levels rise where collisions happen. Also look into Perlin Noise.

( 2a ) Simulate erosion using rainfall. Fluvial erosion can be simulated with spheres "rolling" down the slopes of your terrain. As a drop flows over a node, it takes a small chunk of land with it, reducing the height of the land.

Where the droplets go next is determined by the lowest negative change in elevation amongst your neighboring nodes or tiles. After each erosion round, or even drop, you can smooth the terrain so future drops will know where to drop.

As your drops roll down slopes, they will eventually need to find a stopping point. The most realistic and time-consuming method would be to find water flooding levels to make lakes and oceans. A faster method is to have the drops reduce in size over time and stop when they reach zero.

( 2b ) Generate a water flow map for erosion. This is good for river generation. The basic idea is to find an edge point for flow-off. You can have multiple flow-off points, but you will have to process the river generation algorithm in parallel. The basic idea for the algorithm is

start out by making directed graph(s) for water flow:
    push the edge points onto a stack as seeds;
    while stack is not empty:
        pop a node;
        mark node as visited;
        randomly select a number of backflow forks (1 to 3 usually works);
        select up to that number of unvisited nodes, depending on which are unvisited;
        // this can be done randomly or based on the height of primitive terrain;
        make links from popped node to selected fork nodes;
        push the selected fork nodes;

now simulate flow volume:
    initialize a flow-volume value for each node or tile to be zero;
    for each tile on the map:
        push tile on to a stack;
        while the node stack is not empty:
            pop a node;
            increment the node's flow volume by 1;
            push any backflow neighbors;

You can use the water volume map to decide an amount to erode (depth and radius of dirt dig). Alternatively, you could use it to pre-script drop flow 2a's algorithm. You would have to change the direction of the directed graph arcs though.

( 3 ) After Erosion, you can apply light noise to the terrain for rockiness. I find additive blends of random circle radii to be a useful and fast method. You could also use Perlin noise with higher octaves than what you used for your base terrain. Just remember blurs will soften your slopes and noise will make things sharper.

This will give you a somewhat decent terrain. If you want to go further, you could look into lake generation and cliff generation. You would also have to decide if you want other features like craters, arches, mesas, and towers.

Fractal coastlines and rivers are also worth looking into. I would just get all of Mandelbrot's books and papers on the subject. There is a wealth of info on terrain generation from him, even though his work can be applied to a much greater scope of computer science, and mathematics.

For terrain generation, most of the algorithms are using some kind of Perlin noise .

In Python, implementations already exist. You can check caseman's implementation on GitHub or on the Python package index . The package is under MIT license, which means you can use it without any restriction. If you need other kinds of noise, I've implemented a few noise generators in Python that you can find on my own GitHub .


EDIT: Here is an example of how you could use the module:

import noise

def neighbors(terrain, i, j, L, C):
    possible_neigbors = [(i+di, j+dj) for di in [-1, 0, 1] for dj in [-1, 0, 1]]
    return [terrain[i2][j2] for (i2, j2) in possible_neigbors
              if i2 >= 0 and j2 >= 0 and i2 < L and j2 < C]

def generate_terrain(L, C):
    noisegrid = [[noise.pnoise2(j/C, i/L) for j in range(C)] for i in range(L)]
    terrain = [[int(noisegrid[i][j] > 0.12) for j in range(C)] for i in range(L)]

    for i in range(L):
        for j in range(C):
            if terrain[i][j] == 0:
                nb = neighbors(terrain, i, j, L, C)
                if 1 in nb:
                    terrain[i][j] = 2

    return terrain

terrain = generate_terrain(6, 20)

When I ran this code, it generated:

00211112000000000000
00211112000000000000
00221122000000000000
00021120000000000000

For more control on the terrain shape, or to randomize from one execution to another, please read the comments in the module code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM