Last active
March 10, 2017 11:44
-
-
Save pardo/a3173598f80aac734779a4d87a70531b to your computer and use it in GitHub Desktop.
Random Terrain Generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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