Results 1 to 3 of 3
  1. #1
    exonaut is offline Member
    Join Date
    Mar 2013
    Posts
    15
    Rep Power
    0

    Question Java Random Terrain

    Alright so I'm using Simplex Noise to try and generate a top-down world but I'm running into a few problems. First of all I'm not sure my noise class is optimized or fully functional for 2D top-down terrain, I'll post it below. Secondly I was wondering how to generate the world in chunks at a time but still have each chunk be "pieced" together. Thirdly water always appears in the top-left corner of my chunk which I don't understand why. I'll post all the code I have below, the variables CHUNK_WIDTH and CHUNK_HEIGHT are both 25 and represent 25 tiles wide and high. The variable detail represents a constant to multiply the noise value by to get more detail and it is 100. The rest you should be able to figure out, any feedback or questions are welcome thanks!

    Java Code:
    public static Chunk generateChunk()
    	{
    		Tile[][] tiles = new Tile[Chunk.CHUNK_WIDTH][Chunk.CHUNK_HEIGHT];
    		float[][] noiseValues = new float[Chunk.CHUNK_WIDTH][Chunk.CHUNK_HEIGHT];
    		
    		SimplexNoise.seed();
    		
    		for (int x = 0; x < noiseValues.length; x++)
    		{
    			for (int y = 0; y < noiseValues[x].length; y++)
    			{
    				noiseValues[x][y] = SimplexNoise.generate(x * (0.8f / tiles.length), y * (0.8f / tiles.length)) * detail;
    			}
    		}
    		
    		for (int x = 0; x < tiles.length; x++)
    		{
    			for (int y = 0; y < tiles[x].length; y++)
    			{
    				int noiseValue = Math.abs((int) noiseValues[x][y]);
    				
    				if (noiseValue >= 50)
        				tiles[x][y] = new Tile(new Vector2(x * 32, y * 32), ground);
        			if (noiseValue < 50 && noiseValue >= 25)
        				tiles[x][y] = new Tile(new Vector2(x * 32, y * 32), stone);
        			if (noiseValue < 25)
        				tiles[x][y] = new Tile(new Vector2(x * 32, y * 32), water);
    			}
    		}
    		
    		return new Chunk(tiles);
    	}

    Java Code:
    import java.util.Random;
    
    public class SimplexNoise
    {
        private static int[] perm = new int[] { 151, 160, 137, 91, 90, 15,
            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, 151, 160, 137, 91, 90, 15, 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 };
    
        public static void seed()
        {
            Random rand = new Random();
            for (int iter = 0; iter < perm.length; iter++)
            {
                perm[iter] = rand.nextInt(256);
            }
        }
        
        public static float generate(float x) 
        {
            int i0 = fastFloor(x);
            int i1 = i0 + 1;
            float x0 = x - i0;
            float x1 = x0 - 1.0f;
            float n0, n1;
            float t0 = 1.0f - x0 * x0;
            t0 *= t0;
            n0 = t0 * t0 * grad(perm[i0 & 0xff], x0);
            float t1 = 1.0f - x1 * x1;
            t1 *= t1;
            n1 = t1 * t1 * grad(perm[i1 & 0xff], x1);
            // The maximum value of this noise is 8*(3/4)^4 = 2.53125
            // A factor of 0.395 scales to fit exactly within [-1,1]
            return 0.395f * (n0 + n1);
        }
        
        public static float generate(float x, float y)
        {
            final float F2 = 0.366025403f; // F2 = 0.5*(sqrt(3.0)-1.0)
            final float G2 = 0.211324865f; // G2 = (3.0-Math.sqrt(3.0))/6.0
            float n0, n1, n2; // Noise contributions from the three corners
            // Skew the input space to determine which simplex cell we're in
            float s = (x + y) * F2; // Hairy factor for 2D
            float xs = x + s;
            float ys = y + s;
            int i = fastFloor(xs);
            int j = fastFloor(ys);
            float t = (float)(i + j) * G2;
            float X0 = i - t; // Unskew the cell origin back to (x,y) space
            float Y0 = j - t;
            float x0 = x - X0; // The x,y distances from the cell origin
            float y0 = y - 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
            float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
            float y1 = y0 - j1 + G2;
            float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords
            float y2 = y0 - 1.0f + 2.0f * G2;
            // Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
            int ii = i % 256;
            int jj = j % 256;
            // Calculate the contribution from the three corners
            float t0 = 0.5f - x0 * x0 - y0 * y0;
            if (t0 < 0.0f) n0 = 0.0f;
            else
            {
                t0 *= t0;
                n0 = t0 * t0 * grad(perm[ii + perm[jj]], x0, y0);
            }
            float t1 = 0.5f - x1 * x1 - y1 * y1;
            if (t1 < 0.0f) n1 = 0.0f;
            else
            {
                t1 *= t1;
                n1 = t1 * t1 * grad(perm[ii + i1 + perm[jj + j1]], x1, y1);
            }
            float t2 = 0.5f - x2 * x2 - y2 * y2;
            if (t2 < 0.0f) n2 = 0.0f;
            else
            {
                t2 *= t2;
                n2 = t2 * t2 * grad(perm[ii + 1 + perm[jj + 1]], 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 40.0f * (n0 + n1 + n2); // TODO: The scale factor is preliminary!
        }
    
        private static int fastFloor(float x) 
        {
            return (x > 0) ? ((int) x) : (((int) x) - 1);
        }
    
        private static float grad(int hash, float x) 
        {
            int h = hash & 15;
            float grad = 1.0f + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0
            if ((h & 8) != 0)
                grad = -grad; // Set a random sign for the gradient
            return (grad * x); // Multiply the gradient with the distance
        }
    
        private static float grad(int hash, float x, float y) 
        {
            int h = hash & 7; // Convert low 3 bits of hash code
            float u = h < 4 ? x : y; // into 8 simple gradient directions,
            float v = h < 4 ? y : x; // and compute the dot product with (x,y).
            return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -2.0f * v : 2.0f * v);
        }
    
        private static float grad(int hash, float x, float y, float z) 
        {
            int h = hash & 15; // Convert low 4 bits of hash code into 12 simple
            float u = h < 8 ? x : y; // gradient directions, and compute dot
                                        // product.
            float v = h < 4 ? y : h == 12 || h == 14 ? x : z; // Fix repeats at h =
                                                                // 12 to 15
            return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -v : v);
        }
    
        private static float grad(int hash, float x, float y, float z, float t) 
        {
            int h = hash & 31; // Convert low 5 bits of hash code into 32 simple
            float u = h < 24 ? x : y; // gradient directions, and compute dot
                                        // product.
            float v = h < 16 ? y : z;
            float w = h < 8 ? z : t;
            return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -v : v)
                    + ((h & 4) != 0 ? -w : w);
        }
    }
    Last edited by exonaut; 12-09-2013 at 06:12 AM.

  2. #2
    kjkrum's Avatar
    kjkrum is offline Senior Member
    Join Date
    Apr 2011
    Location
    Tucson, AZ
    Posts
    1,058
    Rep Power
    5

    Default Re: Java Random Terrain

    Google for Amit Patel's blog, Red Blob Games. Procedural terrain generation is one of his interests.
    Get in the habit of using standard Java naming conventions!

  3. #3
    exonaut is offline Member
    Join Date
    Mar 2013
    Posts
    15
    Rep Power
    0

    Default Re: Java Random Terrain

    Quote Originally Posted by kjkrum View Post
    Google for Amit Patel's blog, Red Blob Games. Procedural terrain generation is one of his interests.
    I was hoping to fix my noise, but thanks I'll take a look at this.

Similar Threads

  1. Replies: 0
    Last Post: 01-23-2012, 09:12 AM
  2. What is the standard way of making 2D terrain?
    By TacoManStan in forum New To Java
    Replies: 7
    Last Post: 09-15-2011, 12:57 PM
  3. Replies: 0
    Last Post: 11-23-2010, 08:48 PM
  4. 3D Terrain on Sphere?
    By quddusaliquddus in forum Advanced Java
    Replies: 1
    Last Post: 06-22-2009, 11:50 PM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •