HighMap.java 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package pathgame.tilemap;
  2. import java.util.Random;
  3. /** Class for generating two dimensional highmaps of arbitrary size.
  4. *
  5. * @author kajetan
  6. */
  7. public class HighMap
  8. {
  9. private static final float LOW_FREQUENCY = 8.0f;
  10. private static final float HIGH_FREQUENCY = 7.0f;
  11. /** Returns a generated highmap.
  12. *
  13. * @param seed the seed for the highmap
  14. * @param width the width of the highmap
  15. * @param height the height of the highmap
  16. * @return a generated highmap
  17. */
  18. public static HighMap generate(long seed, int width, int height)
  19. {
  20. HighMap map = new HighMap(seed, width, height);
  21. map.zoom();
  22. return map;
  23. }
  24. private final int width;
  25. private final int height;
  26. private final float data[][];
  27. private final Random r;
  28. private HighMap(long seed, int width, int height)
  29. {
  30. r = new Random(seed);
  31. this.width = width;
  32. this.height = height;
  33. this.data = new float[width][height];
  34. }
  35. /** Returns the value at the given position.
  36. *
  37. * @param x the x coordinate of a position
  38. * @param y the y coordinate of a position
  39. * @return the value at the given position
  40. */
  41. public float get(int x, int y)
  42. {
  43. return data[x][y];
  44. }
  45. private float[][] randomizeBase()
  46. {
  47. // +1 for neighbours
  48. int w = (int) Math.ceil(width / HIGH_FREQUENCY) + 1;
  49. int h = (int) Math.ceil(height / HIGH_FREQUENCY) + 1;
  50. float[][] base = new float[w][h];
  51. for(int x = 0; x < w; x++)
  52. {
  53. for(int y = 0; y < h; y++)
  54. {
  55. base[x][y] = r.nextFloat();
  56. }
  57. }
  58. return base;
  59. }
  60. private float smooth(float[][] base, float x1, float y1)
  61. {
  62. // distance to next exact pixel
  63. float fractX = x1 - (int) x1;
  64. float fractY = y1 - (int) y1;
  65. // neighbour pixel coords
  66. int x2 = ((int) x1 + 1) % width;
  67. int y2 = ((int) y1 + 1) % height;
  68. // interpolate over all 4 pixels, strength varies with distance
  69. float value = 0.0f;
  70. value += (1 - fractX) * (1 - fractY) * base[(int) x1][(int) y1];
  71. value += (1 - fractX) * fractY * base[(int) x1][(int) y2];
  72. value += fractX * (1 - fractY) * base[(int) x2][(int) y1];
  73. value += fractX * fractY * base[(int) x2][(int) y2];
  74. return value;
  75. }
  76. private float turbulence(float[][] base, float x1, float y1)
  77. {
  78. float sum = 0.0f;
  79. sum += smooth(base, x1 / LOW_FREQUENCY, y1 / LOW_FREQUENCY) * LOW_FREQUENCY;
  80. sum += smooth(base, x1 / HIGH_FREQUENCY, y1 / HIGH_FREQUENCY) * HIGH_FREQUENCY;
  81. return sum;
  82. }
  83. private void zoom()
  84. {
  85. float[][] base = randomizeBase();
  86. float min = Float.MAX_VALUE;
  87. float max = Float.MIN_VALUE;
  88. for(int x = 0; x < width; x++)
  89. {
  90. for(int y = 0; y < height; y++)
  91. {
  92. float f = turbulence(base, x, y);
  93. data[x][y] = f;
  94. if(f < min)
  95. {
  96. min = f;
  97. }
  98. if(f > max)
  99. {
  100. max = f;
  101. }
  102. }
  103. }
  104. float f = 1.0f / (max - min);
  105. for(int x = 0; x < width; x++)
  106. {
  107. for(int y = 0; y < height; y++)
  108. {
  109. data[x][y] = (data[x][y] - min) * f;
  110. }
  111. }
  112. }
  113. }