mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
template editor: allow single value
This commit is contained in:
parent
2be590ab24
commit
e3da664e56
3 changed files with 233 additions and 142 deletions
|
|
@ -2322,8 +2322,8 @@
|
||||||
<div style="width:4em">Hill</div>
|
<div style="width:4em">Hill</div>
|
||||||
<i class="icon-trash-empty pointer" data-tip="Remove the step"></i>
|
<i class="icon-trash-empty pointer" data-tip="Remove the step"></i>
|
||||||
<i class="icon-resize-vertical" data-tip="Drag to reorder"></i>
|
<i class="icon-resize-vertical" data-tip="Drag to reorder"></i>
|
||||||
<span>y:<input class="templateY" data-tip="Placement range percentage along Y axis (minY-maxY)" value="47-53"></span>
|
<span>y:<input class="templateY" data-tip="Y axis position in percentage (minY-maxY or Y)" value="47-53"></span>
|
||||||
<span>x:<input class="templateX" data-tip="Placement range percentage along X axis (minX-maxX)" value="65-75"></span>
|
<span>x:<input class="templateX" data-tip="X axis position in percentage (minX-maxX or X)" value="65-75"></span>
|
||||||
<span>h:<input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" value="90-100"></span>
|
<span>h:<input class="templateHeight" data-tip="Blob maximum height, use hyphen to get a random number in range" value="90-100"></span>
|
||||||
<span>n:<input class="templateCount" data-tip="Blobs to add, use hyphen to get a random number in range" value="1"></span>
|
<span>n:<input class="templateCount" data-tip="Blobs to add, use hyphen to get a random number in range" value="1"></span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,49 +1,72 @@
|
||||||
(function (global, factory) {
|
(function (global, factory) {
|
||||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
typeof exports === "object" && typeof module !== "undefined" ? (module.exports = factory()) : typeof define === "function" && define.amd ? define(factory) : (global.HeightmapGenerator = factory());
|
||||||
typeof define === 'function' && define.amd ? define(factory) :
|
})(this, function () {
|
||||||
(global.HeightmapGenerator = factory());
|
"use strict";
|
||||||
}(this, (function () { 'use strict';
|
|
||||||
|
|
||||||
let cells, p;
|
let cells, p;
|
||||||
|
|
||||||
const generate = function() {
|
const generate = function () {
|
||||||
TIME && console.time('generateHeightmap');
|
TIME && console.time("generateHeightmap");
|
||||||
cells = grid.cells, p = grid.points;
|
cells = grid.cells;
|
||||||
|
p = grid.points;
|
||||||
cells.h = new Uint8Array(grid.points.length);
|
cells.h = new Uint8Array(grid.points.length);
|
||||||
|
|
||||||
switch (document.getElementById("templateInput").value) {
|
const template = document.getElementById("templateInput").value;
|
||||||
case "Volcano": templateVolcano(); break;
|
switch (template) {
|
||||||
case "High Island": templateHighIsland(); break;
|
case "Volcano":
|
||||||
case "Low Island": templateLowIsland(); break;
|
templateVolcano();
|
||||||
case "Continents": templateContinents(); break;
|
break;
|
||||||
case "Archipelago": templateArchipelago(); break;
|
case "High Island":
|
||||||
case "Atoll": templateAtoll(); break;
|
templateHighIsland();
|
||||||
case "Mediterranean": templateMediterranean(); break;
|
break;
|
||||||
case "Peninsula": templatePeninsula(); break;
|
case "Low Island":
|
||||||
case "Pangea": templatePangea(); break;
|
templateLowIsland();
|
||||||
case "Isthmus": templateIsthmus(); break;
|
break;
|
||||||
case "Shattered": templateShattered(); break;
|
case "Continents":
|
||||||
|
templateContinents();
|
||||||
|
break;
|
||||||
|
case "Archipelago":
|
||||||
|
templateArchipelago();
|
||||||
|
break;
|
||||||
|
case "Atoll":
|
||||||
|
templateAtoll();
|
||||||
|
break;
|
||||||
|
case "Mediterranean":
|
||||||
|
templateMediterranean();
|
||||||
|
break;
|
||||||
|
case "Peninsula":
|
||||||
|
templatePeninsula();
|
||||||
|
break;
|
||||||
|
case "Pangea":
|
||||||
|
templatePangea();
|
||||||
|
break;
|
||||||
|
case "Isthmus":
|
||||||
|
templateIsthmus();
|
||||||
|
break;
|
||||||
|
case "Shattered":
|
||||||
|
templateShattered();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
TIME && console.timeEnd('generateHeightmap');
|
TIME && console.timeEnd("generateHeightmap");
|
||||||
}
|
};
|
||||||
|
|
||||||
// parse template step
|
// parse template step
|
||||||
function addStep(a1, a2, a3, a4, a5) {
|
function addStep(a1, a2, a3, a4, a5) {
|
||||||
if (a1 === "Hill") addHill(a2, a3, a4, a5); else
|
if (a1 === "Hill") return addHill(a2, a3, a4, a5);
|
||||||
if (a1 === "Pit") addPit(a2, a3, a4, a5); else
|
if (a1 === "Pit") return addPit(a2, a3, a4, a5);
|
||||||
if (a1 === "Range") addRange(a2, a3, a4, a5); else
|
if (a1 === "Range") return addRange(a2, a3, a4, a5);
|
||||||
if (a1 === "Trough") addTrough(a2, a3, a4, a5); else
|
if (a1 === "Trough") return addTrough(a2, a3, a4, a5);
|
||||||
if (a1 === "Strait") addStrait(a2, a3); else
|
if (a1 === "Strait") return addStrait(a2, a3);
|
||||||
if (a1 === "Add") modify(a3, a2, 1); else
|
if (a1 === "Add") return modify(a3, a2, 1);
|
||||||
if (a1 === "Multiply") modify(a3, 0, a2); else
|
if (a1 === "Multiply") return modify(a3, 0, a2);
|
||||||
if (a1 === "Smooth") smooth(a2);
|
if (a1 === "Smooth") return smooth(a2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heighmap Template: Volcano
|
// Heighmap Template: Volcano
|
||||||
function templateVolcano() {
|
function templateVolcano() {
|
||||||
addStep("Hill", "1", "90-100", "44-56", "40-60");
|
addStep("Hill", "1", "90-100", "44-56", "40-60");
|
||||||
addStep("Multiply", .8, "50-100");
|
addStep("Multiply", 0.8, "50-100");
|
||||||
addStep("Range", "1.5", "30-55", "45-55", "40-60");
|
addStep("Range", "1.5", "30-55", "45-55", "40-60");
|
||||||
addStep("Smooth", 2);
|
addStep("Smooth", 2);
|
||||||
addStep("Hill", "1.5", "25-35", "25-30", "20-75");
|
addStep("Hill", "1.5", "25-35", "25-30", "20-75");
|
||||||
|
|
@ -62,7 +85,7 @@
|
||||||
addStep("Trough", "2-3", "20-30", "60-80", "70-80");
|
addStep("Trough", "2-3", "20-30", "60-80", "70-80");
|
||||||
addStep("Hill", "1", "10-15", "60-60", "50-50");
|
addStep("Hill", "1", "10-15", "60-60", "50-50");
|
||||||
addStep("Hill", "1.5", "13-16", "15-20", "20-75");
|
addStep("Hill", "1.5", "13-16", "15-20", "20-75");
|
||||||
addStep("Multiply", .8, "20-100");
|
addStep("Multiply", 0.8, "20-100");
|
||||||
addStep("Range", "1.5", "30-40", "15-85", "30-40");
|
addStep("Range", "1.5", "30-40", "15-85", "30-40");
|
||||||
addStep("Range", "1.5", "30-40", "15-85", "60-70");
|
addStep("Range", "1.5", "30-40", "15-85", "60-70");
|
||||||
addStep("Pit", "2-3", "10-15", "15-85", "20-80");
|
addStep("Pit", "2-3", "10-15", "15-85", "20-80");
|
||||||
|
|
@ -79,14 +102,14 @@
|
||||||
addStep("Hill", "1.5", "10-15", "5-15", "20-80");
|
addStep("Hill", "1.5", "10-15", "5-15", "20-80");
|
||||||
addStep("Hill", "1", "10-15", "85-95", "70-80");
|
addStep("Hill", "1", "10-15", "85-95", "70-80");
|
||||||
addStep("Pit", "3-5", "10-15", "15-85", "20-80");
|
addStep("Pit", "3-5", "10-15", "15-85", "20-80");
|
||||||
addStep("Multiply", .4, "20-100");
|
addStep("Multiply", 0.4, "20-100");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heighmap Template: Continents
|
// Heighmap Template: Continents
|
||||||
function templateContinents() {
|
function templateContinents() {
|
||||||
addStep("Hill", "1", "80-85", "75-80", "40-60");
|
addStep("Hill", "1", "80-85", "75-80", "40-60");
|
||||||
addStep("Hill", "1", "80-85", "20-25", "40-60");
|
addStep("Hill", "1", "80-85", "20-25", "40-60");
|
||||||
addStep("Multiply", .22, "20-100");
|
addStep("Multiply", 0.22, "20-100");
|
||||||
addStep("Hill", "5-6", "15-20", "25-75", "20-82");
|
addStep("Hill", "5-6", "15-20", "25-75", "20-82");
|
||||||
addStep("Range", ".8", "30-60", "5-15", "20-45");
|
addStep("Range", ".8", "30-60", "5-15", "20-45");
|
||||||
addStep("Range", ".8", "30-60", "5-15", "55-80");
|
addStep("Range", ".8", "30-60", "5-15", "55-80");
|
||||||
|
|
@ -118,7 +141,7 @@
|
||||||
addStep("Hill", "1.5", "30-50", "25-75", "30-70");
|
addStep("Hill", "1.5", "30-50", "25-75", "30-70");
|
||||||
addStep("Hill", ".5", "30-50", "25-35", "30-70");
|
addStep("Hill", ".5", "30-50", "25-35", "30-70");
|
||||||
addStep("Smooth", 1);
|
addStep("Smooth", 1);
|
||||||
addStep("Multiply", .2, "25-100");
|
addStep("Multiply", 0.2, "25-100");
|
||||||
addStep("Hill", ".5", "10-20", "50-55", "48-52");
|
addStep("Hill", ".5", "10-20", "50-55", "48-52");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +154,7 @@
|
||||||
addStep("Smooth", 1);
|
addStep("Smooth", 1);
|
||||||
addStep("Hill", "2-3", "30-70", "0-5", "20-80");
|
addStep("Hill", "2-3", "30-70", "0-5", "20-80");
|
||||||
addStep("Hill", "2-3", "30-70", "95-100", "20-80");
|
addStep("Hill", "2-3", "30-70", "95-100", "20-80");
|
||||||
addStep("Multiply", .8, "land");
|
addStep("Multiply", 0.8, "land");
|
||||||
addStep("Trough", "3-5", "40-50", "0-100", "0-10");
|
addStep("Trough", "3-5", "40-50", "0-100", "0-10");
|
||||||
addStep("Trough", "3-5", "40-50", "0-100", "90-100");
|
addStep("Trough", "3-5", "40-50", "0-100", "90-100");
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +179,7 @@
|
||||||
addStep("Hill", "1-2", "5-40", "15-50", "90-100");
|
addStep("Hill", "1-2", "5-40", "15-50", "90-100");
|
||||||
addStep("Hill", "8-12", "20-40", "20-80", "48-52");
|
addStep("Hill", "8-12", "20-40", "20-80", "48-52");
|
||||||
addStep("Smooth", 2);
|
addStep("Smooth", 2);
|
||||||
addStep("Multiply", .7, "land");
|
addStep("Multiply", 0.7, "land");
|
||||||
addStep("Trough", "3-4", "25-35", "5-95", "10-20");
|
addStep("Trough", "3-4", "25-35", "5-95", "10-20");
|
||||||
addStep("Trough", "3-4", "25-35", "5-95", "80-90");
|
addStep("Trough", "3-4", "25-35", "5-95", "80-90");
|
||||||
addStep("Range", "5-6", "30-40", "10-90", "35-65");
|
addStep("Range", "5-6", "30-40", "10-90", "35-65");
|
||||||
|
|
@ -187,48 +210,78 @@
|
||||||
|
|
||||||
function getBlobPower() {
|
function getBlobPower() {
|
||||||
switch (+pointsInput.dataset.cells) {
|
switch (+pointsInput.dataset.cells) {
|
||||||
case 1000: return .93;
|
case 1000:
|
||||||
case 2000: return .95;
|
return 0.93;
|
||||||
case 5000: return .96;
|
case 2000:
|
||||||
case 10000: return .98;
|
return 0.95;
|
||||||
case 20000: return .985;
|
case 5000:
|
||||||
case 30000: return .987;
|
return 0.96;
|
||||||
case 40000: return .9892;
|
case 10000:
|
||||||
case 50000: return .9911;
|
return 0.98;
|
||||||
case 60000: return .9921;
|
case 20000:
|
||||||
case 70000: return .9934;
|
return 0.985;
|
||||||
case 80000: return .9942;
|
case 30000:
|
||||||
case 90000: return .9946;
|
return 0.987;
|
||||||
case 100000: return .995;
|
case 40000:
|
||||||
|
return 0.9892;
|
||||||
|
case 50000:
|
||||||
|
return 0.9911;
|
||||||
|
case 60000:
|
||||||
|
return 0.9921;
|
||||||
|
case 70000:
|
||||||
|
return 0.9934;
|
||||||
|
case 80000:
|
||||||
|
return 0.9942;
|
||||||
|
case 90000:
|
||||||
|
return 0.9946;
|
||||||
|
case 100000:
|
||||||
|
return 0.995;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLinePower() {
|
function getLinePower() {
|
||||||
switch (+pointsInput.dataset.cells) {
|
switch (+pointsInput.dataset.cells) {
|
||||||
case 1000: return .74;
|
case 1000:
|
||||||
case 2000: return .75;
|
return 0.74;
|
||||||
case 5000: return .78;
|
case 2000:
|
||||||
case 10000: return .81;
|
return 0.75;
|
||||||
case 20000: return .82;
|
case 5000:
|
||||||
case 30000: return .83;
|
return 0.78;
|
||||||
case 40000: return .84;
|
case 10000:
|
||||||
case 50000: return .855;
|
return 0.81;
|
||||||
case 60000: return .87;
|
case 20000:
|
||||||
case 70000: return .885;
|
return 0.82;
|
||||||
case 80000: return .91;
|
case 30000:
|
||||||
case 90000: return .92;
|
return 0.83;
|
||||||
case 100000: return .93;
|
case 40000:
|
||||||
|
return 0.84;
|
||||||
|
case 50000:
|
||||||
|
return 0.855;
|
||||||
|
case 60000:
|
||||||
|
return 0.87;
|
||||||
|
case 70000:
|
||||||
|
return 0.885;
|
||||||
|
case 80000:
|
||||||
|
return 0.91;
|
||||||
|
case 90000:
|
||||||
|
return 0.92;
|
||||||
|
case 100000:
|
||||||
|
return 0.93;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const addHill = function(count, height, rangeX, rangeY) {
|
const addHill = function (count, height, rangeX, rangeY) {
|
||||||
count = getNumberInRange(count);
|
count = getNumberInRange(count);
|
||||||
const power = getBlobPower();
|
const power = getBlobPower();
|
||||||
while (count > 0) {addOneHill(); count--;}
|
while (count > 0) {
|
||||||
|
addOneHill();
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
function addOneHill() {
|
function addOneHill() {
|
||||||
const change = new Uint8Array( cells.h.length);
|
const change = new Uint8Array(cells.h.length);
|
||||||
let limit = 0, start;
|
let limit = 0,
|
||||||
|
start;
|
||||||
let h = lim(getNumberInRange(height));
|
let h = lim(getNumberInRange(height));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
@ -236,7 +289,7 @@
|
||||||
const y = getPointInRange(rangeY, graphHeight);
|
const y = getPointInRange(rangeY, graphHeight);
|
||||||
start = findGridCell(x, y);
|
start = findGridCell(x, y);
|
||||||
limit++;
|
limit++;
|
||||||
} while (cells.h[start] + h > 90 && limit < 50)
|
} while (cells.h[start] + h > 90 && limit < 50);
|
||||||
|
|
||||||
change[start] = h;
|
change[start] = h;
|
||||||
const queue = [start];
|
const queue = [start];
|
||||||
|
|
@ -245,23 +298,26 @@
|
||||||
|
|
||||||
for (const c of cells.c[q]) {
|
for (const c of cells.c[q]) {
|
||||||
if (change[c]) continue;
|
if (change[c]) continue;
|
||||||
change[c] = change[q] ** power * (Math.random() * .2 + .9);
|
change[c] = change[q] ** power * (Math.random() * 0.2 + 0.9);
|
||||||
if (change[c] > 1) queue.push(c);
|
if (change[c] > 1) queue.push(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cells.h = cells.h.map((h, i) => lim(h + change[i]));
|
cells.h = cells.h.map((h, i) => lim(h + change[i]));
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
const addPit = function (count, height, rangeX, rangeY) {
|
||||||
|
|
||||||
const addPit = function(count, height, rangeX, rangeY) {
|
|
||||||
count = getNumberInRange(count);
|
count = getNumberInRange(count);
|
||||||
while (count > 0) {addOnePit(); count--;}
|
while (count > 0) {
|
||||||
|
addOnePit();
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
function addOnePit() {
|
function addOnePit() {
|
||||||
const used = new Uint8Array(cells.h.length);
|
const used = new Uint8Array(cells.h.length);
|
||||||
let limit = 0, start;
|
let limit = 0,
|
||||||
|
start;
|
||||||
let h = lim(getNumberInRange(height));
|
let h = lim(getNumberInRange(height));
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
@ -269,28 +325,31 @@
|
||||||
const y = getPointInRange(rangeY, graphHeight);
|
const y = getPointInRange(rangeY, graphHeight);
|
||||||
start = findGridCell(x, y);
|
start = findGridCell(x, y);
|
||||||
limit++;
|
limit++;
|
||||||
} while (cells.h[start] < 20 && limit < 50)
|
} while (cells.h[start] < 20 && limit < 50);
|
||||||
|
|
||||||
const queue = [start];
|
const queue = [start];
|
||||||
while (queue.length) {
|
while (queue.length) {
|
||||||
const q = queue.shift();
|
const q = queue.shift();
|
||||||
h = h ** getBlobPower() * (Math.random() * .2 + .9);
|
h = h ** getBlobPower() * (Math.random() * 0.2 + 0.9);
|
||||||
if (h < 1) return;
|
if (h < 1) return;
|
||||||
|
|
||||||
cells.c[q].forEach(function(c, i) {
|
cells.c[q].forEach(function (c, i) {
|
||||||
if (used[c]) return;
|
if (used[c]) return;
|
||||||
cells.h[c] = lim(cells.h[c] - h * (Math.random() * .2 + .9));
|
cells.h[c] = lim(cells.h[c] - h * (Math.random() * 0.2 + 0.9));
|
||||||
used[c] = 1;
|
used[c] = 1;
|
||||||
queue.push(c);
|
queue.push(c);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const addRange = function(count, height, rangeX, rangeY) {
|
const addRange = function (count, height, rangeX, rangeY) {
|
||||||
count = getNumberInRange(count);
|
count = getNumberInRange(count);
|
||||||
const power = getLinePower();
|
const power = getLinePower();
|
||||||
while (count > 0) {addOneRange(); count--;}
|
while (count > 0) {
|
||||||
|
addOneRange();
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
function addOneRange() {
|
function addOneRange() {
|
||||||
const used = new Uint8Array(cells.h.length);
|
const used = new Uint8Array(cells.h.length);
|
||||||
|
|
@ -300,13 +359,16 @@
|
||||||
const startX = getPointInRange(rangeX, graphWidth);
|
const startX = getPointInRange(rangeX, graphWidth);
|
||||||
const startY = getPointInRange(rangeY, graphHeight);
|
const startY = getPointInRange(rangeY, graphHeight);
|
||||||
|
|
||||||
let dist = 0, limit = 0, endX, endY;
|
let dist = 0,
|
||||||
|
limit = 0,
|
||||||
|
endX,
|
||||||
|
endY;
|
||||||
do {
|
do {
|
||||||
endX = Math.random() * graphWidth * .8 + graphWidth * .1;
|
endX = Math.random() * graphWidth * 0.8 + graphWidth * 0.1;
|
||||||
endY = Math.random() * graphHeight * .7 + graphHeight * .15;
|
endY = Math.random() * graphHeight * 0.7 + graphHeight * 0.15;
|
||||||
dist = Math.abs(endY - startY) + Math.abs(endX - startX);
|
dist = Math.abs(endY - startY) + Math.abs(endX - startX);
|
||||||
limit++;
|
limit++;
|
||||||
} while ((dist < graphWidth / 8 || dist > graphWidth / 3) && limit < 50)
|
} while ((dist < graphWidth / 8 || dist > graphWidth / 3) && limit < 50);
|
||||||
|
|
||||||
let range = getRange(findGridCell(startX, startY), findGridCell(endX, endY));
|
let range = getRange(findGridCell(startX, startY), findGridCell(endX, endY));
|
||||||
|
|
||||||
|
|
@ -317,11 +379,14 @@
|
||||||
|
|
||||||
while (cur !== end) {
|
while (cur !== end) {
|
||||||
let min = Infinity;
|
let min = Infinity;
|
||||||
cells.c[cur].forEach(function(e) {
|
cells.c[cur].forEach(function (e) {
|
||||||
if (used[e]) return;
|
if (used[e]) return;
|
||||||
let diff = (p[end][0] - p[e][0]) ** 2 + (p[end][1] - p[e][1]) ** 2;
|
let diff = (p[end][0] - p[e][0]) ** 2 + (p[end][1] - p[e][1]) ** 2;
|
||||||
if (Math.random() > .85) diff = diff / 2;
|
if (Math.random() > 0.85) diff = diff / 2;
|
||||||
if (diff < min) {min = diff; cur = e;}
|
if (diff < min) {
|
||||||
|
min = diff;
|
||||||
|
cur = e;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (min === Infinity) return range;
|
if (min === Infinity) return range;
|
||||||
range.push(cur);
|
range.push(cur);
|
||||||
|
|
@ -332,25 +397,29 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// add height to ridge and cells around
|
// add height to ridge and cells around
|
||||||
let queue = range.slice(), i = 0;
|
let queue = range.slice(),
|
||||||
|
i = 0;
|
||||||
while (queue.length) {
|
while (queue.length) {
|
||||||
const frontier = queue.slice();
|
const frontier = queue.slice();
|
||||||
queue = [], i++;
|
(queue = []), i++;
|
||||||
frontier.forEach(i => {
|
frontier.forEach(i => {
|
||||||
cells.h[i] = lim(cells.h[i] + h * (Math.random() * .3 + .85));
|
cells.h[i] = lim(cells.h[i] + h * (Math.random() * 0.3 + 0.85));
|
||||||
});
|
});
|
||||||
h = h ** power - 1;
|
h = h ** power - 1;
|
||||||
if (h < 2) break;
|
if (h < 2) break;
|
||||||
frontier.forEach(f => {
|
frontier.forEach(f => {
|
||||||
cells.c[f].forEach(i => {
|
cells.c[f].forEach(i => {
|
||||||
if (!used[i]) {queue.push(i); used[i] = 1;}
|
if (!used[i]) {
|
||||||
|
queue.push(i);
|
||||||
|
used[i] = 1;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate prominences
|
// generate prominences
|
||||||
range.forEach((cur, d) => {
|
range.forEach((cur, d) => {
|
||||||
if (d%6 !== 0) return;
|
if (d % 6 !== 0) return;
|
||||||
for (const l of d3.range(i)) {
|
for (const l of d3.range(i)) {
|
||||||
const min = cells.c[cur][d3.scan(cells.c[cur], (a, b) => cells.h[a] - cells.h[b])]; // downhill cell
|
const min = cells.c[cur][d3.scan(cells.c[cur], (a, b) => cells.h[a] - cells.h[b])]; // downhill cell
|
||||||
//debug.append("circle").attr("cx", p[min][0]).attr("cy", p[min][1]).attr("r", 1);
|
//debug.append("circle").attr("cx", p[min][0]).attr("cy", p[min][1]).attr("r", 1);
|
||||||
|
|
@ -358,35 +427,43 @@
|
||||||
cur = min;
|
cur = min;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const addTrough = function(count, height, rangeX, rangeY) {
|
const addTrough = function (count, height, rangeX, rangeY) {
|
||||||
count = getNumberInRange(count);
|
count = getNumberInRange(count);
|
||||||
const power = getLinePower();
|
const power = getLinePower();
|
||||||
while (count > 0) {addOneTrough(); count--;}
|
while (count > 0) {
|
||||||
|
addOneTrough();
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
function addOneTrough() {
|
function addOneTrough() {
|
||||||
const used = new Uint8Array(cells.h.length);
|
const used = new Uint8Array(cells.h.length);
|
||||||
let h = lim(getNumberInRange(height));
|
let h = lim(getNumberInRange(height));
|
||||||
|
|
||||||
// find start and end points
|
// find start and end points
|
||||||
let limit = 0, startX, startY, start, dist = 0, endX, endY;
|
let limit = 0,
|
||||||
|
startX,
|
||||||
|
startY,
|
||||||
|
start,
|
||||||
|
dist = 0,
|
||||||
|
endX,
|
||||||
|
endY;
|
||||||
do {
|
do {
|
||||||
startX = getPointInRange(rangeX, graphWidth);
|
startX = getPointInRange(rangeX, graphWidth);
|
||||||
startY = getPointInRange(rangeY, graphHeight);
|
startY = getPointInRange(rangeY, graphHeight);
|
||||||
start = findGridCell(startX, startY);
|
start = findGridCell(startX, startY);
|
||||||
limit++;
|
limit++;
|
||||||
} while (cells.h[start] < 20 && limit < 50)
|
} while (cells.h[start] < 20 && limit < 50);
|
||||||
|
|
||||||
limit = 0;
|
limit = 0;
|
||||||
do {
|
do {
|
||||||
endX = Math.random() * graphWidth * .8 + graphWidth * .1;
|
endX = Math.random() * graphWidth * 0.8 + graphWidth * 0.1;
|
||||||
endY = Math.random() * graphHeight * .7 + graphHeight * .15;
|
endY = Math.random() * graphHeight * 0.7 + graphHeight * 0.15;
|
||||||
dist = Math.abs(endY - startY) + Math.abs(endX - startX);
|
dist = Math.abs(endY - startY) + Math.abs(endX - startX);
|
||||||
limit++;
|
limit++;
|
||||||
} while ((dist < graphWidth / 8 || dist > graphWidth / 2) && limit < 50)
|
} while ((dist < graphWidth / 8 || dist > graphWidth / 2) && limit < 50);
|
||||||
|
|
||||||
let range = getRange(start, findGridCell(endX, endY));
|
let range = getRange(start, findGridCell(endX, endY));
|
||||||
|
|
||||||
|
|
@ -397,11 +474,14 @@
|
||||||
|
|
||||||
while (cur !== end) {
|
while (cur !== end) {
|
||||||
let min = Infinity;
|
let min = Infinity;
|
||||||
cells.c[cur].forEach(function(e) {
|
cells.c[cur].forEach(function (e) {
|
||||||
if (used[e]) return;
|
if (used[e]) return;
|
||||||
let diff = (p[end][0] - p[e][0]) ** 2 + (p[end][1] - p[e][1]) ** 2;
|
let diff = (p[end][0] - p[e][0]) ** 2 + (p[end][1] - p[e][1]) ** 2;
|
||||||
if (Math.random() > .8) diff = diff / 2;
|
if (Math.random() > 0.8) diff = diff / 2;
|
||||||
if (diff < min) {min = diff; cur = e;}
|
if (diff < min) {
|
||||||
|
min = diff;
|
||||||
|
cur = e;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
if (min === Infinity) return range;
|
if (min === Infinity) return range;
|
||||||
range.push(cur);
|
range.push(cur);
|
||||||
|
|
@ -412,25 +492,29 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// add height to ridge and cells around
|
// add height to ridge and cells around
|
||||||
let queue = range.slice(), i = 0;
|
let queue = range.slice(),
|
||||||
|
i = 0;
|
||||||
while (queue.length) {
|
while (queue.length) {
|
||||||
const frontier = queue.slice();
|
const frontier = queue.slice();
|
||||||
queue = [], i++;
|
(queue = []), i++;
|
||||||
frontier.forEach(i => {
|
frontier.forEach(i => {
|
||||||
cells.h[i] = lim(cells.h[i] - h * (Math.random() * .3 + .85));
|
cells.h[i] = lim(cells.h[i] - h * (Math.random() * 0.3 + 0.85));
|
||||||
});
|
});
|
||||||
h = h ** power - 1;
|
h = h ** power - 1;
|
||||||
if (h < 2) break;
|
if (h < 2) break;
|
||||||
frontier.forEach(f => {
|
frontier.forEach(f => {
|
||||||
cells.c[f].forEach(i => {
|
cells.c[f].forEach(i => {
|
||||||
if (!used[i]) {queue.push(i); used[i] = 1;}
|
if (!used[i]) {
|
||||||
|
queue.push(i);
|
||||||
|
used[i] = 1;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate prominences
|
// generate prominences
|
||||||
range.forEach((cur, d) => {
|
range.forEach((cur, d) => {
|
||||||
if (d%6 !== 0) return;
|
if (d % 6 !== 0) return;
|
||||||
for (const l of d3.range(i)) {
|
for (const l of d3.range(i)) {
|
||||||
const min = cells.c[cur][d3.scan(cells.c[cur], (a, b) => cells.h[a] - cells.h[b])]; // downhill cell
|
const min = cells.c[cur][d3.scan(cells.c[cur], (a, b) => cells.h[a] - cells.h[b])]; // downhill cell
|
||||||
//debug.append("circle").attr("cx", p[min][0]).attr("cy", p[min][1]).attr("r", 1);
|
//debug.append("circle").attr("cx", p[min][0]).attr("cy", p[min][1]).attr("r", 1);
|
||||||
|
|
@ -438,21 +522,21 @@
|
||||||
cur = min;
|
cur = min;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const addStrait = function(width, direction = "vertical") {
|
const addStrait = function (width, direction = "vertical") {
|
||||||
width = Math.min(getNumberInRange(width), grid.cellsX/3);
|
width = Math.min(getNumberInRange(width), grid.cellsX / 3);
|
||||||
if (width < 1 && P(width)) return;
|
if (width < 1 && P(width)) return;
|
||||||
const used = new Uint8Array(cells.h.length);
|
const used = new Uint8Array(cells.h.length);
|
||||||
const vert = direction === "vertical";
|
const vert = direction === "vertical";
|
||||||
const startX = vert ? Math.floor(Math.random() * graphWidth * .4 + graphWidth * .3) : 5;
|
const startX = vert ? Math.floor(Math.random() * graphWidth * 0.4 + graphWidth * 0.3) : 5;
|
||||||
const startY = vert ? 5 : Math.floor(Math.random() * graphHeight * .4 + graphHeight * .3);
|
const startY = vert ? 5 : Math.floor(Math.random() * graphHeight * 0.4 + graphHeight * 0.3);
|
||||||
const endX = vert ? Math.floor((graphWidth - startX) - (graphWidth * .1) + (Math.random() * graphWidth * .2)) : graphWidth - 5;
|
const endX = vert ? Math.floor(graphWidth - startX - graphWidth * 0.1 + Math.random() * graphWidth * 0.2) : graphWidth - 5;
|
||||||
const endY = vert ? graphHeight - 5 : Math.floor((graphHeight - startY) - (graphHeight * .1) + (Math.random() * graphHeight * .2));
|
const endY = vert ? graphHeight - 5 : Math.floor(graphHeight - startY - graphHeight * 0.1 + Math.random() * graphHeight * 0.2);
|
||||||
|
|
||||||
const start = findGridCell(startX, startY), end = findGridCell(endX, endY);
|
const start = findGridCell(startX, startY),
|
||||||
|
end = findGridCell(endX, endY);
|
||||||
let range = getRange(start, end);
|
let range = getRange(start, end);
|
||||||
const query = [];
|
const query = [];
|
||||||
|
|
||||||
|
|
@ -461,10 +545,13 @@
|
||||||
|
|
||||||
while (cur !== end) {
|
while (cur !== end) {
|
||||||
let min = Infinity;
|
let min = Infinity;
|
||||||
cells.c[cur].forEach(function(e) {
|
cells.c[cur].forEach(function (e) {
|
||||||
let diff = (p[end][0] - p[e][0]) ** 2 + (p[end][1] - p[e][1]) ** 2;
|
let diff = (p[end][0] - p[e][0]) ** 2 + (p[end][1] - p[e][1]) ** 2;
|
||||||
if (Math.random() > 0.8) diff = diff / 2;
|
if (Math.random() > 0.8) diff = diff / 2;
|
||||||
if (diff < min) {min = diff; cur = e;}
|
if (diff < min) {
|
||||||
|
min = diff;
|
||||||
|
cur = e;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
range.push(cur);
|
range.push(cur);
|
||||||
}
|
}
|
||||||
|
|
@ -472,12 +559,12 @@
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
const step = .1 / width;
|
const step = 0.1 / width;
|
||||||
|
|
||||||
while (width > 0) {
|
while (width > 0) {
|
||||||
const exp = .9 - step * width;
|
const exp = 0.9 - step * width;
|
||||||
range.forEach(function(r) {
|
range.forEach(function (r) {
|
||||||
cells.c[r].forEach(function(e) {
|
cells.c[r].forEach(function (e) {
|
||||||
if (used[e]) return;
|
if (used[e]) return;
|
||||||
used[e] = 1;
|
used[e] = 1;
|
||||||
query.push(e);
|
query.push(e);
|
||||||
|
|
@ -486,39 +573,42 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
range = query.slice();
|
range = query.slice();
|
||||||
|
|
||||||
width--;
|
width--;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const modify = function(range, add, mult, power) {
|
const modify = function (range, add, mult, power) {
|
||||||
const min = range === "land" ? 20 : range === "all" ? 0 : +range.split("-")[0];
|
const min = range === "land" ? 20 : range === "all" ? 0 : +range.split("-")[0];
|
||||||
const max = range === "land" || range === "all" ? 100 : +range.split("-")[1];
|
const max = range === "land" || range === "all" ? 100 : +range.split("-")[1];
|
||||||
grid.cells.h = grid.cells.h.map(h => h >= min && h <= max ? mod(h) : h);
|
grid.cells.h = grid.cells.h.map(h => (h >= min && h <= max ? mod(h) : h));
|
||||||
|
|
||||||
function mod(v) {
|
function mod(v) {
|
||||||
if (add) v = min === 20 ? Math.max(v + add, 20) : v + add;
|
if (add) v = min === 20 ? Math.max(v + add, 20) : v + add;
|
||||||
if (mult !== 1) v = min === 20 ? (v-20) * mult + 20 : v * mult;
|
if (mult !== 1) v = min === 20 ? (v - 20) * mult + 20 : v * mult;
|
||||||
if (power) v = min === 20 ? (v-20) ** power + 20 : v ** power;
|
if (power) v = min === 20 ? (v - 20) ** power + 20 : v ** power;
|
||||||
return lim(v);
|
return lim(v);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const smooth = function(fr = 2, add = 0) {
|
const smooth = function (fr = 2, add = 0) {
|
||||||
cells.h = cells.h.map((h, i) => {
|
cells.h = cells.h.map((h, i) => {
|
||||||
const a = [h];
|
const a = [h];
|
||||||
cells.c[i].forEach(c => a.push(cells.h[c]));
|
cells.c[i].forEach(c => a.push(cells.h[c]));
|
||||||
return lim((h * (fr-1) + d3.mean(a) + add) / fr);
|
return lim((h * (fr - 1) + d3.mean(a) + add) / fr);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
function getPointInRange(range, length) {
|
function getPointInRange(range, length) {
|
||||||
if (typeof range !== "string") {ERROR && console.error("Range should be a string"); return;}
|
if (typeof range !== "string") {
|
||||||
const min = range.split("-")[0]/100 || 0;
|
ERROR && console.error("Range should be a string");
|
||||||
const max = range.split("-")[1]/100 || 100;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const min = range.split("-")[0] / 100 || 0;
|
||||||
|
const max = range.split("-")[1] / 100 || min;
|
||||||
return rand(min * length, max * length);
|
return rand(min * length, max * length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {generate, addHill, addRange, addTrough, addStrait, addPit, smooth, modify};
|
return {generate, addHill, addRange, addTrough, addStrait, addPit, smooth, modify};
|
||||||
|
});
|
||||||
})));
|
|
||||||
|
|
|
||||||
|
|
@ -950,7 +950,8 @@ function editHeightmap() {
|
||||||
|
|
||||||
for (const s of steps) {
|
for (const s of steps) {
|
||||||
if (s.style.opacity == 0.5) continue;
|
if (s.style.opacity == 0.5) continue;
|
||||||
const type = s.getAttribute("data-type");
|
const type = s.dataset.type;
|
||||||
|
|
||||||
const elCount = s.querySelector(".templateCount") || "";
|
const elCount = s.querySelector(".templateCount") || "";
|
||||||
const elHeight = s.querySelector(".templateHeight") || "";
|
const elHeight = s.querySelector(".templateHeight") || "";
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue