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; } } } }