LWJGL: Procedurally Generated Simplex/Perlin Noise 2D world

Hi,

I am trying to create a procedurally generating world for a 2D platformer similar to the likes of Terraria or Starbound, but in Java/LWJGL

These are examples of what I am trying to achieve:
http://www.youtube.com/watch?v=SwHWhPaxbHA (Preferrably this one)
http://www.youtube.com/watch?v=tv7wFF97odI

I would like to know how I should best go about doing this as there seems to be pretty much nothing in the way of tutorials for 1d perlin noise procedural generation.

Thanks,

  • Dan

I found this simplex noise generator somewhere online.


public class SimplexNoise {  // Simplex noise in 2D, 3D and 4D

	  public static int RANDOMSEED=0;
	  private static int NUMBEROFSWAPS=400;  

	  private static Grad grad3[] = {new Grad(1,1,0),new Grad(-1,1,0),new Grad(1,-1,0),new Grad(-1,-1,0),
	                                 new Grad(1,0,1),new Grad(-1,0,1),new Grad(1,0,-1),new Grad(-1,0,-1),
	                                 new Grad(0,1,1),new Grad(0,-1,1),new Grad(0,1,-1),new Grad(0,-1,-1)};

	  private static short p_supply[] = {151,160,137,91,90,15, //this contains all the numbers between 0 and 255, these are put in a random order depending upon the seed
	  131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
	  190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
	  88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
	  77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
	  102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
	  135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
	  5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
	  223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
	  129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
	  251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
	  49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
	  138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180};

	  private short p[]=new short[p_supply.length];

	  // To remove the need for index wrapping, double the permutation table length
	  private short perm[] = new short[512];
	  private short permMod12[] = new short[512];
	  public SimplexNoise() {
		
	    p=p_supply.clone();

	    int seed = SimplexNoise.RANDOMSEED;
	    
	    if (seed==RANDOMSEED){
	        Random rand=new Random();
	        seed=rand.nextInt();
	    }

	    //the random for the swaps
	    Random rand=new Random(seed);

	    //the seed determines the swaps that occur between the default order and the order we're actually going to use
	    for(int i=0;i<NUMBEROFSWAPS;i++){
	        int swapFrom=rand.nextInt(p.length);
	        int swapTo=rand.nextInt(p.length);

	        short temp=p[swapFrom];
	        p[swapFrom]=p[swapTo];
	        p[swapTo]=temp;
	    }


	    for(int i=0; i<512; i++)
	    {
	      perm[i]=p[i & 255];
	      permMod12[i] = (short)(perm[i] % 12);
	    }
	  }

	  // Skewing and unskewing factors for 2, 3, and 4 dimensions
	  private static final double F2 = 0.5*(Math.sqrt(3.0)-1.0);
	  private static final double G2 = (3.0-Math.sqrt(3.0))/6.0;

	  // This method is a *lot* faster than using (int)Math.floor(x)
	  private static int fastfloor(double x) {
	    int xi = (int)x;
	    return x<xi ? xi-1 : xi;
	  }

	  private static double dot(Grad g, double x, double y) {
	    return g.x*x + g.y*y; }


	  // 2D simplex noise
	  public float noise(float xin, float yin) {
	    double n0, n1, n2; // Noise contributions from the three corners
	    // Skew the input space to determine which simplex cell we're in
	    double s = (xin+yin)*F2; // Hairy factor for 2D
	    int i = fastfloor(xin+s);
	    int j = fastfloor(yin+s);
	    double t = (i+j)*G2;
	    double X0 = i-t; // Unskew the cell origin back to (x,y) space
	    double Y0 = j-t;
	    double x0 = xin-X0; // The x,y distances from the cell origin
	    double y0 = yin-Y0;
	    // For the 2D case, the simplex shape is an equilateral triangle.
	    // Determine which simplex we are in.
	    int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
	    if(x0>y0) {i1=1; j1=0;} // lower triangle, XY order: (0,0)->(1,0)->(1,1)
	    else {i1=0; j1=1;}      // upper triangle, YX order: (0,0)->(0,1)->(1,1)
	    // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
	    // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
	    // c = (3-sqrt(3))/6
	    double x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
	    double y1 = y0 - j1 + G2;
	    double x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords
	    double y2 = y0 - 1.0 + 2.0 * G2;
	    // Work out the hashed gradient indices of the three simplex corners
	    int ii = i & 255;
	    int jj = j & 255;
	    int gi0 = permMod12[ii+perm[jj]];
	    int gi1 = permMod12[ii+i1+perm[jj+j1]];
	    int gi2 = permMod12[ii+1+perm[jj+1]];
	    // Calculate the contribution from the three corners
	    double t0 = 0.5 - x0*x0-y0*y0;
	    if(t0<0) n0 = 0.0;
	    else {
	      t0 *= t0;
	      n0 = t0 * t0 * dot(grad3[gi0], x0, y0);  // (x,y) of grad3 used for 2D gradient
	    }
	    double t1 = 0.5 - x1*x1-y1*y1;
	    if(t1<0) n1 = 0.0;
	    else {
	      t1 *= t1;
	      n1 = t1 * t1 * dot(grad3[gi1], x1, y1);
	    }
	    double t2 = 0.5 - x2*x2-y2*y2;
	    if(t2<0) n2 = 0.0;
	    else {
	      t2 *= t2;
	      n2 = t2 * t2 * dot(grad3[gi2], x2, y2);
	    }
	    // Add contributions from each corner to get the final noise value.
	    // The result is scaled to return values in the interval [-1,1].
	    return (float) (70.0 * (n0 + n1 + n2));
	  }



	  // Inner class to speed upp gradient computations
	  // (array access is a lot slower than member access)
	  private static class Grad
	  {
	    double x, y;

	    Grad(double x, double y, double z)
	    {
	      this.x = x;
	      this.y = y;
	    }

	  }

	}

I don’t really think there is a point in trying to understand it, unless you really need to…

Great thanks, do you have the link where you found that for reference?

Thanks

  • Dan

I found a good tutorial on perlin noise. It should be enough for a simple game :open_mouth: If you’re making 1d, 2d noise, perlin noise is plenty.

http://webstaff.itn.liu.se/~stegu/TNM022-2005/perlinnoiselinks/perlin-noise-math-faq.html

Uhm here is the full code for simplex noise.
I think…
http://webstaff.itn.liu.se/~stegu/simplexnoise/SimplexNoise.java

Hi just having a look at the code, thanks for helping,

Sorry, I’m a bit of a novice when it comes to world generation and perlin noise, how should I use the code, like draw it in a function for example?

Thanks,

  • Dan

Noise cannot be generated every render cycle. Its too expensive. You can create an array of tiles, which would contain tiles with x,y coordinates. Now, you put those x,y tile coordinates into PerlinNoise.noise(double xin, double yin) method, and it will give you a height. You need to divide the x,y by some factor, because otherwise your tiles will look completely random. Simplex/Perlin noise basically interpolates data. You should just take a look at Perlin noise tutorial I put a link to. So, when you put in x,y coordinates, do something like .noise((float) x / 30, (float) y / 30). Now that you have a height from this method, you can use it to determine what kind of tile it should be. Lets say that height values from -1 to 0 will be dirt tiles, and tiles with height 0 to 1 will be grass tiles. You just check that height and put in the tile into your array of tiles.

After you made your tile array, you just render it.

Right thanks, sorry to ask this, but could you give me a basic example of how I could do that?

Here is how I was drawing a basic line of tiles as an example:


		// Draw the ground

		glBegin(GL_QUADS);

		glColor3d(0.6, 0.2, 0.1);
		glVertex2d(0, 0);
		glVertex2d(Display.getWidth(), 0);

		glVertex2d(Display.getWidth(), 32);
		glVertex2d(0, 32);

		glEnd();

		// Draw the grass

		glBegin(GL_QUADS);

		glColor3d(0.2, 0.8, 0.2);
		glVertex2d(0, 25);
		glVertex2d(Display.getWidth(), 25);

		glVertex2d(Display.getWidth(), 32);
		glVertex2d(0, 32);

		glEnd();

Thanks,

  • Dan

http://pastebin.java-gaming.org/ad503871884

Here is the code…

You can adjust values such as:

  • width, height, size, frequency to change the look of output :smiley:
    Press R to recalculate tiles.

I assume you put your native path for LWJGL in your project already.

Hi,
Thanks for that it seems to work well, however, it is top down and I need it to be for a sidescroller (like terraria)

How can I modify that code so that it works for that? or do you have a different way I could render it so that it is a sidescrolling map as opposed to top down?

Thanks so much for you help I really appreciate it!

  • Dan

I changed makeTiles method only.


	private void makeTiles() {

		tiles = new int[width * height];

		SimplexNoise noise = new SimplexNoise();

		int freq = 30;
		
		for(int x=0;x<width;x++) {
			float h = (noise.noise((float) x / freq, 0) + 1) / 2; // make noise 0 to 1
			
			for(int y=0;y<height;y++) {
				float current = (float) (height - y) / height;
				
				if(current > h) tiles[x+y*width]=2;
				else tiles[x+y*width]=1;
				
			}
		}

	}

Awesome thats pretty great, just a question, my background is now the green tile for some reason, and it should be this:


		// Draw the sky
		glBegin(GL_QUADS);

		glColor3d(0.7, 0.8, 0.9);
		glVertex2d(0, 0);
		glVertex2d(Display.getWidth(), 0);

		glColor3d(0.5, 0.6, 0.8);
		glVertex2d(Display.getWidth(), Display.getHeight());
		glVertex2d(0, Display.getHeight());

		glEnd();

so that should be the background and the grass should be just on the edge of the dirt

Thanks so much for your help,

  • Dan

Sorry to be annoying, but did you see the message about the sky and the grass not quite working properly?

Thanks,

  • Dan

Lol i don’t think you’re annoying to anyone.

Its just I don’t think you realize that you don’t understand a thing in my code, because you’re asking such simple question. I can make the whole game for you if you want, if you pay me of course :smiley:

This isn’t the place to ask to make games. This is a place to discuss / ask for help. And the help should be technical, such as “How can I change opengl rendering color?” or “how can I render a quad using opengl?” although you should first try to google such question, and if you can’t find the answers, then post a question here! :slight_smile:

You should try to make your own games / implementations. If you can’t generate terraria looking terrain, then its not the time to do it yet.

I mean, your first question was how to generate terrain from perlin / simplex noise and I answered that question :slight_smile:
If your background is green, you need to change the color of the tile that is being rendered in the “back ground”. So when you render background tile, you could try rendering it with color 1f, 1f, 1f.

Right yes sorry nevermind, I do understand most of the code, but am still wrapping my head around LWJGL.

Thanks so much mate,

  • Dan