Infinite, random, non-repeating 2d terrain generation

Dear programmers,
I’m new to the Forum and not new to Processing Java mode.
I’ve been searching on the Internet for days to find an algorithm that is able to generate 2d terrain endlessly, and randomly but also natural looking like in MineCraft for example.

What I’ve been trying is the in Java Processing mode implemented Perlin’s noise function, which is very cool and useful. However it has one downside I’ve discovered, it repeats consistently the pattern every 256…

As I mentioned before, I couldn’t find an easy explanation to avoid this. What I’ve got in mind is seperating the map in chunks and for each chunk I can use a random noiseSeed, with a value from the randSeed. The problem with this is that the borders between chunks will be too obvious and for example hills and rivers won’t line up each other between two chunks.

Please could someone provide an easy-understandable solution to this? It doesn’t matter if it is in Processing Java mode code (not too long) or an explanation how MineCraft or other games are able to load and connect those random generated chunks, because it has been done, so there is an answer to that.

Hopefully you can help me, it’s sooo difficult…, especially all is explained in English, and my main language is Dutch… Even studying Calculus integration (even by parts and (trig) substitution) is easier than figuring out this problem…

Thank you in advance,
Warm regards,
spaces

Check out Sebastian lague. He has a terrain generation playlist on YouTube. Code is in unity but what he talks about is transferable. Its currently a bit beyond me atm but I have implemented static terrain maps.

1 Like

To get around chunk borders so you need simply need to equalise the values (in the 2D gradient lattice) of adjacent vertices between chunks.


So, to seamlessly append a chunk on the right side of an initial chunk (like above), generate the chunk’s lattice then overwrite the vertices in its left-most row with the gradient values from green vertices of the initial chunk.

1 Like

Thank you for your reactions.

Paulgoux, this is basically doable in Processing for me, creating chunks that are endlessly going on. My problem would be matching repeating chunks together… I haven’t started randomizing chunks yet. Here is the script that loads the endless terrain but repeating the same patterns consistently as the main function of Perlin noise though… Hopefully the “Preformatted text” on the forum work:

int pix_siz=3,move_speed=15,chunk_siz=200;//The bigger the pixel size the faster it will load. The bigger move speed the faster you move around. You can also adjust chunksize.
float scl=0.03;//The scale emphasizes the steps, which is stated in the documentary of Processing: "Steps of 0.005-0.03 work best for most applications, but this will differ depending on use."
PVector move=new PVector(0,0);//So that you can move in the world around.
boolean mouse_pressed=false,redraw=true;//Yes... there is a redraw() function in Processing, but I prefer using booleans...
char[]key_inputs={'w','a','s','d'};//Your keycontrols, currently 'wasd'.
boolean[]key_outputs=new boolean[4];//This will allow you to move around, using wasd (like in games).
void setup(){
  noiseSeed(0);//I want the world to be able to be reloaded again by using a seed like in MineCraft.
  //Just sets screensize.
  surface.setSize(displayWidth,displayHeight);
  surface.setResizable(true);
  //
}
void draw(){
  if(redraw){
    //This will let multiple keyinputs work.
    PVector[]adjustments={new PVector(0,-move_speed),new PVector(-move_speed,0),new PVector(0,move_speed),new PVector(move_speed,0)};
    for(int i=0;i<key_inputs.length;i++){
      if(key_outputs[i]){
        move.add(adjustments[i]);
      }
    }
    //
    //This will draw the terrain using Perlin noise.
    noStroke();//Deleting the ugly strokes of the default settings of rect().
    /*For is like the summation mark in maths. This part draws the terrain using a grayscale.
    I put these noise values into linear equations so that the script is shorter.*/
    for(int i=0;i<width;i+=pix_siz){
      for(int j=0;j<height;j+=pix_siz){
        //fill(map(noise((i+move.x)*scl,(j+move.y)*scl),0,1,0,255));//<---- for grayscale.
        fill(lerpColor(color(0,0,255),color(255,0,0),noise((i+move.x)*scl,(j+move.y)*scl)));
        rect(i,j,pix_siz,pix_siz);
      }
    }
    //
    //This will sychronize chunks to terrain:
    if(mouse_pressed){
      //If mouse is pressed, chunkborders will be shown.
      strokeWeight(pix_siz);
      stroke(0);
      pushMatrix();
      translate(-move.x%chunk_siz,-move.y%chunk_siz);//Only loads the chunk borders that are visible on screen.
      for(int i=-chunk_siz;i<width+chunk_siz;i+=chunk_siz){
        for(int j=-chunk_siz;j<height+chunk_siz;j+=chunk_siz){
          fill(0,0,0,0);//Transparant rectangle.
          rect(i,j,chunk_siz,chunk_siz);
        }
      }
      popMatrix();
    }
    //
    redraw=false;//Stop drawing, Processing!!!
  }
}
void mousePressed(){
  mouse_pressed=true;
  redraw=true;
}
void mouseReleased(){
  mouse_pressed=false;
  redraw=true;
}
void keyPressed(){
  Key_Controls(true);//To make it shorter, I've made an apart function for that key input/output thingie.
}
void keyReleased(){
  Key_Controls(false);
}
void Key_Controls(boolean a){
  //This connects with the draw function.
  for(int i=0;i<key_inputs.length;i++){
    if(key==key_inputs[i]){
      key_outputs[i]=a;
    }
  }
  redraw=true;
}

Micycle, thank you for your brief explanation. Do you mean generating the initial chunk and another one, then placing it next to each other and putting the values of the border line of two chunks together? What’s the best way to overwrite the border, so that the chunks will match up together, taking the average of those values, summing up etc?

I might have given you the wrong video in the playlist. In any case he defffo mentions the problem you currently have and provides a solution though I understand you might not want to watch the entire thing.

If I were to attempt this again I would calculate the center grid. And have 4 arrays which will store the first and last row and the 1st and last column. Then I would calculate the other grids I guess clockwise though this wouldn’t really matter providing that you correctly match the array to the right tile.

As an aside this would actually require 8 or more tiles depending on how many tiles you want to render for the scene. Also note once you make the jump to 3d resolution might change depending on distance from the center.

Do you mean generating the initial chunk and another one, then placing it next to each other and putting the values of the border line of two chunks together? What’s the best way to overwrite the border, so that the chunks will match up together, taking the average of those values, summing up etc?

Just to clarify, by values I’m referring to the grid that the perlin noise uses to interpolate over, not the noise(x,y) values. So this would of course require computing a new grid (just how Processing does to get its 256x256, or thereabouts, grid) for each chunk.

I think you could just overwrite adjacent rows with the row in the previous chunk, but I suppose interpolating would work too.

Here’s a 1D example of tiling the same noise by interpolating – the same principle would apply to 2D, but you want it to be infinite too.