-1

I'm trying to code multiplayer tile-base java game.(Just for fun)

World map created using Perlin Noise. So I'm interested, how can I create really large map?

For example to generate 8000x8000 map with Perlin noise requires about 4096Mb of RAM.

Map represented as [8000][8000] array, but after generating I store it in database, but I want to create map about 25000x25000 tiles in it. Can I divide map generating process into smaller parts? The problem is that I should use a Perlin noise for the whole map, otherwise map will looks like just couple of chunks, or if you know something about dynamic map generation, please tell me. I am shocked how it works in Minecraft (I mean new generated chunks somehow connected with prevous).

Here is my code:

public static float[][] generateWhiteNoise(int width, int height)
   {
       Random random = new Random(); //Seed to 0 for testing
       float[][] noise = new float[width][height];

       for (int i = 0; i < width; i++)
       {
           for (int j = 0; j < height; j++)
           {
               noise[i][j] = (float)random.nextDouble() % 1;
           }
       }
       return noise;
   }



static float Interpolate(float x0, float x1, float alpha)
   {
       return x0 * (1 - alpha) + alpha * x1;
   }

static float[][] generateSmoothNoise(float[][] baseNoise, int octave)
   {
       int width = baseNoise.length;
       int height = baseNoise[0].length;

       float[][] smoothNoise = new float[width][height];

       int samplePeriod = 1 << octave; // calculates 2 ^ k
       float sampleFrequency = 1.0f / samplePeriod;

       for (int i = 0; i < width; i++)
       {
           //calculate the horizontal sampling indices
           int sample_i0 = (i / samplePeriod) * samplePeriod;
           int sample_i1 = (sample_i0 + samplePeriod) % width; //wrap around
           float horizontal_blend = (i - sample_i0) * sampleFrequency;

           for (int j = 0; j < height; j++)
           {
               //calculate the vertical sampling indices
               int sample_j0 = (j / samplePeriod) * samplePeriod;
               int sample_j1 = (sample_j0 + samplePeriod) % height; //wrap around
               float vertical_blend = (j - sample_j0) * sampleFrequency;

               //blend the top two corners
               float top = Interpolate(baseNoise[sample_i0][sample_j0],
                  baseNoise[sample_i1][sample_j0], horizontal_blend);

               //blend the bottom two corners
               float bottom = Interpolate(baseNoise[sample_i0][sample_j1],
                  baseNoise[sample_i1][sample_j1], horizontal_blend);

               //final blend
               smoothNoise[i][j] = Interpolate(top, bottom, vertical_blend);
           }
       }
       return smoothNoise;
   }

static float[][] generatePerlinNoise(float[][] baseNoise, int octaveCount)
   {
       int width = baseNoise.length;
       int height = baseNoise[0].length;

       float[][][] smoothNoise = new float[octaveCount][][]; //an array of 2D arrays containing

       float persistance = 0.5f;

       //generate smooth noise
       for (int i = 0; i < octaveCount; i++)
       {
           smoothNoise[i] = generateSmoothNoise(baseNoise, i);
       }

       float[][] perlinNoise = new float[width][height];
       float amplitude = 1.0f;
       float totalAmplitude = 0.0f;

       //blend noise together
       for (int octave = octaveCount - 1; octave >= 0; octave--)
       {
           amplitude *= persistance;
           totalAmplitude += amplitude;

           for (int i = 0; i < width; i++)
           {
               for (int j = 0; j < height; j++)
               {
                   perlinNoise[i][j] += smoothNoise[octave][i][j] * amplitude;
               }
           }
       }

       //normalisation
       for (int i = 0; i < width; i++)
       {
           for (int j = 0; j < height; j++)
           {
               perlinNoise[i][j] /= totalAmplitude;
           }
       }
       return perlinNoise;
   }
user3696488
  • 53
  • 1
  • 5
  • 1
    Perlin noise is amazing because it just "ends up" connecting. If your perlin noise algorithm is correct you should be able to create chunks at any size in any order and it won't affect the terrain – Richard Tingle Jun 01 '14 at 10:15
  • Well, firstly I create white nosie, and then Prlin noise based on white noise and it's size. I don't understand how can I connect 2 absolutely different chunks?(with smooth border) – user3696488 Jun 01 '14 at 10:32
  • Are you using several octaves and combining them to create fractal noise? I wrote a little bit on this in the [simplex noise tag wiki](http://stackoverflow.com/tags/simplex-noise/info) (simplex noise is just upgraded perlin noise) and in this [answer about minecraft biomes](http://programmers.stackexchange.com/questions/202992/randomization-of-biomes/203040#203040). But broadly; you sample reproducable noise on several length scales. Post your current code and examples of its incorrect output and I'll have a look – Richard Tingle Jun 01 '14 at 10:35
  • What are you using the white noise for? – user253751 Jun 01 '14 at 10:38

2 Answers2

1

Now, you are probably generating the noise with java.util.Random. You will need to replace this with a mixing function. Your perlin noise generator should be a stateless function. Something like this:

int noise(int x, int y) {
    return (x*31)^(y*41); // mix x and y pseudorandomly
}

double smoothNoise(double x, double y) {
    return noise(floor(x),floor(y)) * fract(x) + ... // interpolate
}

double perlinNoise(double x, double y) {
   return smoothNoise(x,y)*0.5 +
          smoothNoise(x/2,y/2)*0.25 + ... // add octaves
}

This way, you can call perlinNoise whenever you like and it will always return the same results. This will allow you to generate your map in chunks without visible seams.

Community
  • 1
  • 1
Piotr Praszmo
  • 17,928
  • 1
  • 57
  • 65
0

I see two options:

  1. Use something which implements hard drive backed map (or even do it yourself since it's rather easy)
  2. Use full fledged database to dynamically save chunks of the generated map, probably with proxy pattern (since you are using Perlin noise you will need to access various parts of the map).

My vote goes to database.

nrph
  • 335
  • 7
  • 18