terrain-map
ARCHIVED - repo for blog post http://www.vogt.world/writing/procedural-terrain-generation/
git clone https://git.vogt.world/terrain-map.git
Log | Files | README.md
← Commit log
commit
message
Added Greedy Raindrop algorithm
author
Ben Vogt <[email protected]>
date
2016-05-14 01:45:54
stats
2 file(s) changed, 124 insertions(+), 6 deletions(-)
files
index.html
main.js
  1diff --git a/index.html b/index.html
  2index 847ef4b..5aaf051 100644
  3--- a/index.html
  4+++ b/index.html
  5@@ -16,9 +16,7 @@
  6     <div class="container">
  7       <hr>
  8       <div class="row">
  9-        <h2>
 10-          Standard Diamond-Square algorithm
 11-        </h2>
 12+        <h2>Standard Diamond-Square algorithm</h2>
 13         <p>
 14           Diamon-Square with smoothing of 10, and 20.
 15           <button class="run button-primary" id="standard">RUN</button>
 16@@ -28,8 +26,8 @@
 17       <hr>
 18       <div class="row">
 19         <h2>
 20-          Combining Diamond-Square maps
 21-        </h2>
 22+              Combining Diamond-Square maps
 23+            </h2>
 24         <p>
 25           Combining a DS, DS smoothed (10), and DS smoothed (20) maps. This is done by generating <code>standard</code>, then <code>standard-two</code>, a completely different map. Then using each of these to generate a smoothed version of themselves. Then
 26           we can combine standard with <code>standard-10</code>, using <code>standard-two-20</code> as the map controlling which parts of the map are used for the result. For example the higher the value of a given point on <code>standard-two-20</code>, the
 27@@ -47,13 +45,24 @@
 28     <div class="hidden">
 29       <canvas id="tmp" width="256" height="256"></canvas>
 30     </div>
 31+    <hr>
 32+    <div class="container">
 33+      <div class="row">
 34+        <h2>Greedy Raindrop Erosion Algorithm</h2>
 35+        <p>
 36+          For each point on the map, steal a certain percentage off the tallest neighbor. Results in blochy, plateau-like formations.
 37+          <button class="run button-primary" id="grd">RUN</button>
 38+        </p>
 39+      </div>
 40+      <div class="set-of" id="container-3"></div>
 41+    </div>
 42     <div class="container">
 43       <hr>
 44       <div class="row">
 45         <p>
 46           That's all!
 47         </p>
 48-      </div>.
 49+      </div>
 50     </div>
 51   </body>
 52 </html>
 53diff --git a/main.js b/main.js
 54index 32e5550..36de5bf 100644
 55--- a/main.js
 56+++ b/main.js
 57@@ -1,4 +1,4 @@
 58-$(document).ready(function(){
 59+$(document).ready(function() {
 60   function LandMap(options) {
 61     var level = 8;
 62     this.containerId = options.containerId;
 63@@ -149,6 +149,101 @@ $(document).ready(function(){
 64     }
 65   };
 66 
 67+  LandMap.prototype.grd = function(amount, percent, featureFrom, featureTo) {
 68+    this.maps[featureTo] = new Array(this.size * this.size);
 69+
 70+    for (var y = 0; y < this.size; y++) {
 71+      for (var x = 0; x < this.size; x++) {
 72+        this.set(featureTo, x, y, this.get(featureFrom, x, y));
 73+      }
 74+    }
 75+
 76+    var operationAray = new Array(this.size * this.size);
 77+    var size = this.size
 78+    for (var y = 0; y < this.size; y++) {
 79+      for (var x = 0; x < this.size; x++) {
 80+        operationAray[(x + size * y)] = [0];
 81+      }
 82+    }
 83+
 84+    var MARGIN = amount;
 85+    for (var i = 0; i < MARGIN; i++) {
 86+      operationAray[(x + this.size * y)] = [0];
 87+      var max = Number.MIN_SAFE_INTEGER;
 88+      var min = Number.MAX_SAFE_INTEGER;
 89+      for (var y = 0; y < this.size; y++) {
 90+        for (var x = 0; x < this.size; x++) {
 91+          var val = this.get(featureTo, x, y);
 92+          if (val !== undefined) {
 93+            max = Math.max(max, val);
 94+            min = Math.min(min, val);
 95+          }
 96+        }
 97+      }
 98+
 99+      // iterate through all
100+      for (var y = MARGIN; y < this.size - MARGIN; y++) {
101+        for (var x = MARGIN; x < this.size - MARGIN; x++) {
102+          var neighbors = [
103+            this.get(featureTo, x - 1, y),
104+            this.get(featureTo, x + 1, y),
105+            this.get(featureTo, x, y - 1),
106+            this.get(featureTo, x, y + 1)
107+          ];
108+          operationAray[(x + size * y)].push(this.get(featureTo, x, y));
109+          var index = indexOfMax(featureTo);
110+          var thisValue = this.get(featureTo, x, y);
111+          if (neighbors[index] > thisValue) {
112+            if (index == 0) {
113+              // WEST (left)
114+              operationAray[(x + size * y)].push(this.get(featureTo, x - 1, y) * percent);
115+              operationAray[((x - 1) + size * y)].push(this.get(featureTo, x - 1, y) * (percent) * (-1));
116+            } else if (index == 1) {
117+              // EAST (right)
118+              operationAray[(x + size * y)].push(this.get(featureTo, x + 1, y) * percent);
119+              operationAray[((x + 1) + size * y)].push(this.get(featureTo, x + 1, y) * (percent) * (-1));
120+            } else if (index == 2) {
121+              // NORTH (up)
122+              operationAray[(x + size * y)].push(this.get(featureTo, x, y - 1) * percent);
123+              operationAray[(x + size * (y - 1))].push(this.get(featureTo, x - 1, y) * (percent) * (-1));
124+            } else if (index == 3) {
125+              // SOUTH (down)
126+              operationAray[(x + size * y)].push(this.get(featureTo, x, y + 1) * percent);
127+              operationAray[(x + size * (y + 1))].push(this.get(featureTo, x, y + 1) * (percent) * (-1));
128+            }
129+          }
130+        }
131+      }
132+      //iterate through summing the operationAray, and setting it
133+      for (var y = MARGIN; y < size - MARGIN; y++) {
134+        for (var x = MARGIN; x < size - MARGIN; x++) {
135+          var value = operationAray[(x + size * y)].reduce(function(a, b) {
136+            return a + b;
137+          }, 0);
138+          this.set(featureTo, x, y, value);
139+          operationAray[(x + size * y)] = [value];
140+        }
141+      }
142+    }
143+
144+    function indexOfMax(arr) {
145+      if (arr.length === 0) {
146+        return -1;
147+      }
148+
149+      var max = arr[0];
150+      var maxIndex = 0;
151+
152+      for (var ind = 1; ind < arr.length; ind++) {
153+        if (arr[ind] > max) {
154+          maxIndex = ind;
155+          max = arr[ind];
156+        }
157+      }
158+      return maxIndex;
159+    }
160+  };
161+
162   LandMap.prototype.draw = function() {
163     var html = '<div class="row">';
164     var featureCount = 0;
165@@ -229,4 +324,16 @@ $(document).ready(function(){
166     terrain.combine("standard-10", "standard", "standard-two-20", "reversed");
167     terrain.draw();
168   });
169+
170+  $("#grd").click(function() {
171+    var terrain = new LandMap({
172+      containerId: "container-3"
173+    });
174+    terrain.generate(0.75, "standard");
175+    terrain.grd(22, 0.01, "standard", "grd-22-0.01");
176+    terrain.grd(20, 0.03, "standard", "grd-20-0.03");
177+    terrain.grd(40, 0.01, "standard", "grd-40-0.01");
178+    terrain.draw();
179+  });
180+
181 })