HighMap.java 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. package pathgame.tilemap;
  2. import java.util.Random;
  3. public class HighMap {
  4. private static final float LOW_FREQUENCY = 8.0f;
  5. private static final float HIGH_FREQUENCY = 7.0f;
  6. public static HighMap generate(long seed, int width, int height) {
  7. HighMap map = new HighMap(seed, width, height);
  8. map.zoom();
  9. return map;
  10. }
  11. private final int width;
  12. private final int height;
  13. private final float data[][];
  14. private final Random r;
  15. private HighMap(long seed, int width, int height) {
  16. r = new Random(seed);
  17. this.width = width;
  18. this.height = height;
  19. this.data = new float[width][height];
  20. }
  21. public float get(int x, int y) {
  22. return data[x][y];
  23. }
  24. private float[][] randomizeBase() {
  25. int w = (int) Math.ceil(width / HIGH_FREQUENCY) + 1;
  26. int h = (int) Math.ceil(height / HIGH_FREQUENCY) + 1;
  27. float[][] base = new float[w][h];
  28. for(int x = 0; x < w; x++) {
  29. for(int y = 0; y < h; y++) {
  30. base[x][y] = r.nextFloat();
  31. }
  32. }
  33. return base;
  34. }
  35. private float smooth(float[][] base, float x1, float y1) {
  36. // distance to next exact pixel
  37. float fractX = x1 - (int) x1;
  38. float fractY = y1 - (int) y1;
  39. // neighbour pixel coords
  40. int x2 = ((int) x1 + 1) % width;
  41. int y2 = ((int) y1 + 1) % height;
  42. // interpolate over all 4 pixels, strength varies with distance
  43. float value = 0.0f;
  44. value += (1 - fractX) * (1 - fractY) * base[(int) x1][(int) y1];
  45. value += (1 - fractX) * fractY * base[(int) x1][(int) y2];
  46. value += fractX * (1 - fractY) * base[(int) x2][(int) y1];
  47. value += fractX * fractY * base[(int) x2][(int) y2];
  48. return value;
  49. }
  50. private float turbulence(float[][] base, float x1, float y1) {
  51. float sum = 0.0f;
  52. sum += smooth(base, x1 / LOW_FREQUENCY, y1 / LOW_FREQUENCY) * LOW_FREQUENCY;
  53. sum += smooth(base, x1 / HIGH_FREQUENCY, y1 / HIGH_FREQUENCY) * HIGH_FREQUENCY;
  54. return sum;
  55. }
  56. private void zoom() {
  57. float[][] base = randomizeBase();
  58. float min = Float.MAX_VALUE;
  59. float max = Float.MIN_VALUE;
  60. for(int x = 0; x < width; x++) {
  61. for(int y = 0; y < height; y++) {
  62. float f = turbulence(base, x, y);
  63. data[x][y] = f;
  64. if(f < min) {
  65. min = f;
  66. }
  67. if(f > max) {
  68. max = f;
  69. }
  70. }
  71. }
  72. float f = 1.0f / (max - min);
  73. for(int x = 0; x < width; x++) {
  74. for(int y = 0; y < height; y++) {
  75. data[x][y] = (data[x][y] - min) * f;
  76. }
  77. }
  78. }
  79. }