123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- package pathgame.tilemap;
- import java.util.Random;
- /** Class for generating two dimensional highmaps of arbitrary size.
- *
- * @author kajetan
- */
- public class HighMap
- {
- private static final float LOW_FREQUENCY = 8.0f;
- private static final float HIGH_FREQUENCY = 7.0f;
-
- /** Returns a generated highmap.
- *
- * @param seed the seed for the highmap
- * @param width the width of the highmap
- * @param height the height of the highmap
- * @return a generated highmap
- */
- public static HighMap generate(long seed, int width, int height)
- {
- HighMap map = new HighMap(seed, width, height);
- map.zoom();
- return map;
- }
-
- private final int width;
- private final int height;
- private final float data[][];
- private final Random r;
-
- private HighMap(long seed, int width, int height)
- {
- r = new Random(seed);
- this.width = width;
- this.height = height;
- this.data = new float[width][height];
- }
-
- /** Returns the value at the given position.
- *
- * @param x the x coordinate of a position
- * @param y the y coordinate of a position
- * @return the value at the given position
- */
- public float get(int x, int y)
- {
- return data[x][y];
- }
-
- private float[][] randomizeBase()
- {
- // +1 for neighbours
- int w = (int) Math.ceil(width / HIGH_FREQUENCY) + 1;
- int h = (int) Math.ceil(height / HIGH_FREQUENCY) + 1;
- float[][] base = new float[w][h];
- for(int x = 0; x < w; x++)
- {
- for(int y = 0; y < h; y++)
- {
- base[x][y] = r.nextFloat();
- }
- }
- return base;
- }
-
- private float smooth(float[][] base, float x1, float y1)
- {
- // distance to next exact pixel
- float fractX = x1 - (int) x1;
- float fractY = y1 - (int) y1;
- // neighbour pixel coords
- int x2 = ((int) x1 + 1) % width;
- int y2 = ((int) y1 + 1) % height;
-
- // interpolate over all 4 pixels, strength varies with distance
- float value = 0.0f;
- value += (1 - fractX) * (1 - fractY) * base[(int) x1][(int) y1];
- value += (1 - fractX) * fractY * base[(int) x1][(int) y2];
- value += fractX * (1 - fractY) * base[(int) x2][(int) y1];
- value += fractX * fractY * base[(int) x2][(int) y2];
- return value;
- }
-
- private float turbulence(float[][] base, float x1, float y1)
- {
- float sum = 0.0f;
- sum += smooth(base, x1 / LOW_FREQUENCY, y1 / LOW_FREQUENCY) * LOW_FREQUENCY;
- sum += smooth(base, x1 / HIGH_FREQUENCY, y1 / HIGH_FREQUENCY) * HIGH_FREQUENCY;
- return sum;
- }
-
- private void zoom()
- {
- float[][] base = randomizeBase();
-
- float min = Float.MAX_VALUE;
- float max = Float.MIN_VALUE;
-
- for(int x = 0; x < width; x++)
- {
- for(int y = 0; y < height; y++)
- {
- float f = turbulence(base, x, y);
- data[x][y] = f;
- if(f < min)
- {
- min = f;
- }
- if(f > max)
- {
- max = f;
- }
- }
- }
-
- float f = 1.0f / (max - min);
- for(int x = 0; x < width; x++)
- {
- for(int y = 0; y < height; y++)
- {
- data[x][y] = (data[x][y] - min) * f;
- }
- }
- }
- }
|