2d Landscape Creation Using Perlin Noise (Tile Based)

I am studying perlin noise for an application that I am working on, mainly in the form of a game (simulation), which is a “2-dimensional side view”. I don’t quite understand how perlin noise works, but I get a general idea.

I found this article with the Perlin Noise code and decided to give it back, since I have a global community that is currently created, each “piece” has 16x16 tiles, and I just stated that if Y> = HEIGHT / 2, do all the tiles are “solid” yet “air” to work .. but the earth is very flat, as you might imagine. Thats where I thought perlin noise would appear, so I used the code found on the above website, but I'm not sure how to translate the noise to a solid / airy stove.

As you can see, the terrain is not very realistic enter image description here

I am looking more for the landscape as shown below. should look like mountains and hills) I'm not worried about sharp edges (square) enter image description here

I'm not sure how to iterate through an array of tiles to enable noise above

Right now I'm repeating the tile array (2d) like this, but as you can see in the first shot, it just randomizes whether the tile is solid or not. She does not create any hills or mountains. p>

for(int Y = 0;Y < HEIGHT;++Y) { for(int X = 0;X < WIDTH;++X) { Tile Tile; if(noise(X,Y) < 0) { Tile.Type = BLOCK; } else { Tile.Type = Air; } // Then I push the Tile on to a vector 

I should also mention that to the right of this 16x16 'chunk' there is another piece that should match this, and the same goes with the next piece after that. The pieces should not be the same as the previous ones, just make them not look like separate pieces, if that makes sense.

Any help is much appreciated! Thanks you

UPDATE

I changed my perlin functions to this , and I implemented what Fresnel suggested:

  PerlinNoise *test=new PerlinNoise(0.25, 6); //0.25 is Persistance 6 is Octaves float f,h; float seed = 804.343; for (int X=0; X!=MAP_WIDTH; ++X) { f = test->GetNoise((X * ChunkX) * seed); h = f * MAP_HEIGHT + (MAP_HEIGHT / 2); for (int y=0; y<h; ++y) { Tile tempTile; tempTile.Tile = TILE_NONE; Tiles[X][y] = tempTile; } for (int y=h; y<MAP_HEIGHT; ++y) { Tile tempTile; tempTile.TileID = TILE_BLOCK; Tiles[X][y] = tempTile; } } 

After that, it looks much better, I X * ChunkX for every noise, as if I would not have every piece the same, so now it looks like this enter image description here

As you can see, the landscape is more than what I want than before, but still not very similar to the real landscape, since in its not very smooth form I can do something to smooth out the general appearance of it, to create Rolling hills and plains

I removed tile creation under these noise values ​​to make it easier to see the range enter image description here

As you can see, this looks fine, you just need to “smooth out” the values ​​so that they do not look like pseudo-random values. I also wonder why the first fragment, as seen on the left, has the same meanings as at the very beginning.

Thanks.

+6
source share
1 answer

Your results are good because you have islands, continents, ponds and seas. The Perlin noise helps to generate a random, nonrandom character.

Basically, you reduce (mathematically) the infinite resolution of the noise function into a discrete set of two different fragments along with a very limited block resolution. Given that your result seems to be excellent.

Various things can improve your result. For example, lerp between your tile graphics:

 // Exemplary p-code, fine-tuning required Color color_at (x, y) { Real u = x / width, v = y / height Real f = min (max(noise(u,v), 0), 1); Color c = water*f + hill*(1-f); return c; } 

You can generalize your lerp function to any number of fragments.

Another possibility for sharp edges is based on Voronoi diagrams (1) . You have the same functions as above, but instead of interpolating you take the tile closest to the noise value:

 Color color_at (x, y) { Real u = x / width, v = y / height Real f = min (max(noise(u,v), 0), 1); if (f<0.5) return water; else return hill; } 

This is the same as yours, except that you do it pixel by pixel. Again, this can be generalized.

Once you have a good setup, you can use the noise for everything: the distribution of plants / trees, the spread of the enemy, animations (this will be the 1d-noise function), etc.


Change as your comment:

Adjacent 1d relief:

If you need a side view, as in a classic 2d jump and start, think about the 1d-noise function, iterate from 0 to the image width, take a noise function sample f at each stop, convert f to screen space, then each pixel above will be a part of the sky, each pixel below will be taken from your fragments:

 for (int x=0; x!=width; ++x) { // Get noise value: f = noise1d (x/width); h = f * height + (height/2); // scale and center at screen-center // Select tile: Tile *tile; if (h < waterLimit) { h = waterLimit; tile = waterTile; } else { tile = terrainTile; } // Draw vertical line: for (int y=0; y<h; ++y) setPixel (x, y, skyColor(x,y)); for (int y=h; y<height; ++y) setPixel (x, y, tileColor(x,y, tile)); } 

Again, an approximate pseudocode.

Full 2d levels in your current setup:

The noise function is very flexible. If you want less blue and greener, just omit the constant term, i.e. Instead of if(h < 0) -> blue , do if(h < -0.25) -> blue .


1: I have never tried this approach as I am involved in 3D rendering ( picogen.org )

+4
source

Source: https://habr.com/ru/post/913611/


All Articles