Skip to content

Instantly share code, notes, and snippets.

@pardo
Last active March 10, 2017 11:44
Show Gist options
  • Save pardo/a3173598f80aac734779a4d87a70531b to your computer and use it in GitHub Desktop.
Save pardo/a3173598f80aac734779a4d87a70531b to your computer and use it in GitHub Desktop.
Random Terrain Generator
<html>
<head>
<style>
body, html {
margin: 0;
padding: 0;
height: 100vh;
width: 100vw;
overflow: none;
}
canvas {
}
</style>
</head>
<body>
<canvas id="land"></canvas>
</body>
<script src="main.js" type="application/javascript"></script>
</html>
// Iterative midpoint vertical displacement
function locationOf(element, array, comparer, start, end) {
if (array.length === 0)
return -1;
start = start || 0;
end = end || array.length;
var pivot = (start + end) >> 1; // should be faster than the above calculation
var c = comparer(element, array[pivot]);
if (end - start <= 1) return c == -1 ? pivot - 1 : pivot;
switch (c) {
case -1: return locationOf(element, array, comparer, start, pivot);
case 0: return pivot;
case 1: return locationOf(element, array, comparer, pivot, end);
};
};
// sample for objects like {lastName: 'Miller', ...}
var cmpPoint = function (a, b) {
if (a[0] < b[0]) return -1;
if (a[0] > b[0]) return 1;
return 0;
}
Array.prototype.insertOrdered = function (element, cmp) {
var array = this.slice();
array.splice(locationOf(element, array, cmp) + 1, 0, element);
return array;
};
function midpoint_displacement(start, end, roughness, vertical_displacement, num_of_iterations){
/*
Given a straight line segment specified by a starting point and an endpoint
in the form of [starting_point_x, starting_point_y] and [endpoint_x, endpoint_y],
a roughness value > 0, an initial vertical displacement and a number of
iterations > 0 applies the midpoint algorithm to the specified segment and
returns the obtained list of points in the form
points = [[x_0, y_0],[x_1, y_1],...,[x_n, y_n]]
*/
if (!num_of_iterations) { num_of_iterations = 16 }
// Final number of points = (2^iterations)+1
if (vertical_displacement == null) {
// if no initial displacement is specified set displacement to:
// (y_start+y_end)/2
vertical_displacement = (start[1]+end[1])/2
}
// Data structure that stores the points is a list of lists where
// each sublist represents a point and holds its x and y coordinates:
// points=[[x_0, y_0],[x_1, y_1],...,[x_n, y_n]]
// | | |
// point 0 point 1 point n
// The points list is always kept sorted from smallest to biggest x-value
var points = [start, end];
var iteration = 1;
while( iteration <= num_of_iterations ){
// Since the list of points will be dynamically updated with the new computed
// points after each midpoint displacement it is necessary to create a copy
// of the state at the beginning of the iteration so we can iterate over
// the original sequence.
// Tuple type is used for security reasons since they are immutable in Python.
var points_tup = points.slice();
for (var i=0; i<points_tup.length-1; i++) {
// Calculate x and y midpoint coordinates:
var midpoint = [
(points_tup[i][0]+points_tup[i+1][0])/2,
(points_tup[i][1]+points_tup[i+1][1])/2
];
// Displace midpoint y-coordinate
midpoint[1] += (Math.random()> 0.5)?-vertical_displacement:vertical_displacement;
// Insert the displaced midpoint in the current list of points
points = points.insertOrdered(midpoint, cmpPoint);
}
// Reduce displacement range
vertical_displacement *= 2 ** (-roughness)
// update number of iterations
iteration += 1
}
return points
}
function draw(points, color, clear) {
var canvas = document.getElementById('land');
var c2 = canvas.getContext('2d');
if (clear) {
c2.clearRect(0, 0, canvas.width, canvas.height);
}
c2.fillStyle = color;
c2.beginPath();
c2.moveTo(0, canvas.height);
for (var i=0; i<points.length; i++) {
c2.lineTo(points[i][0], canvas.height-points[i][1]);
}
c2.lineTo(canvas.width, canvas.height);
c2.closePath();
c2.fill();
}
function doLandscape(){
var colors;
if (Math.random()>0.5) {
colors = [
"rgb(195, 157, 224)",
"rgb(158, 98, 204)",
"rgb(130, 79, 138)",
"rgb(68, 28, 99)",
"rgb(49, 7, 82)",
"rgb(23, 3, 38)",
"rbg(240, 203, 163)"
];
} else {
colors = [
"#db3806", "#e0571d", "#e23a18", "#e83d12", "#f46633", "#ff8000"
];
}
var height = 0;
var width = 0;
window.onresize = function(){
var positionInfo = document.getElementsByTagName("body")[0].getBoundingClientRect();
height = positionInfo.height;
width = positionInfo.width;
var canvas = document.getElementsByTagName('canvas')[0];
canvas.width = width;
canvas.height = height;
canvas.style.width = width+'px';
canvas.style.height = height+'px';
};
window.onresize();
var layer_1 = midpoint_displacement([250, 0], [width, 200], 1.4, 20, 12)
var layer_2 = midpoint_displacement([0, 180], [width, 80], 1.2, 30, 12)
var layer_3 = midpoint_displacement([0, 270], [width, 190], 1, 120, 9)
var layer_4 = midpoint_displacement([0, 350], [width, 320], 0.9, 250, 8)
var layer_5 = midpoint_displacement([0, 50], [width, 50], 0.9, 15, 4)
var layer_6 = midpoint_displacement([0, 20], [width, 20], 0.9, 10, 4)
var layer_7 = midpoint_displacement([0, 10], [width, 20], 0.9, 20, 4)
draw(layer_4, colors[0], true);
draw(layer_3, colors[1]);
draw(layer_2, colors[2]);
draw(layer_1, colors[3]);
draw(layer_5, colors[4]);
draw(layer_6, colors[5]);
draw(layer_7, colors[6]);
}
doLandscape();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment