init'
This commit is contained in:
BIN
tutorials/terrainGen/Jagged_Terrain.jpg
Normal file
BIN
tutorials/terrainGen/Jagged_Terrain.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
8
tutorials/terrainGen/dot.js
Normal file
8
tutorials/terrainGen/dot.js
Normal file
@@ -0,0 +1,8 @@
|
||||
class dot{
|
||||
|
||||
constructor(x, y){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
}
|
||||
107
tutorials/terrainGen/index.html
Normal file
107
tutorials/terrainGen/index.html
Normal file
@@ -0,0 +1,107 @@
|
||||
<html>
|
||||
<title>Midpoint Displacement</title>
|
||||
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto"
|
||||
rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Inconsolata"
|
||||
rel="stylesheet">
|
||||
<link rel"shortcut icon" type"image/ico" href"/Media/iconImage.ico">
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
|
||||
<button id="backButton"
|
||||
onclick="window.location.href='../../tutorials.html'">Back</button>
|
||||
|
||||
<head>
|
||||
|
||||
<h1>Midpoint Displacement</h1>
|
||||
|
||||
<p>Midpoint displacement is a common way to generate terrains in video
|
||||
games. Instead of manually creating a stage you can make an
|
||||
algorithm create one based off randomness. This is faster to
|
||||
calculate than a perlin noise stage which is why it can be found
|
||||
frequently in older video game titles.</p><br>
|
||||
<p>Psudo code:</p>
|
||||
<div class="psudoCode">
|
||||
<ul>
|
||||
<li>Create two points.</li>
|
||||
<li>Find the center x coordinate.</li>
|
||||
<li>Create a new point in between the two first points with some
|
||||
offset in the y coorindate.</li>
|
||||
<li>Repeat. (can be recursive)</li>
|
||||
</div>
|
||||
<br>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<p>This canvas starts off with two points in an array called
|
||||
<a>points[]</a>, one at <a>height/2</a> and one at
|
||||
<a>math.random(-vertical_displacement, vertical_displacement)</a>.
|
||||
The center point is found and a new point is made and added to the
|
||||
array. This new point is offset on the y-axis by an amount however
|
||||
we can't use the same <a>vertical_displacement</a> as we did before
|
||||
as we'd end up with a very jagged terrain.
|
||||
</p>
|
||||
<img class="examples" src="Jagged_Terrain.jpg">
|
||||
|
||||
<p>Instead we have to iterate our variable -
|
||||
<a>vertical_displacement</a> - based on the iteration number of the
|
||||
sketch, in order to generate a smooth stage/terrain.
|
||||
</p>
|
||||
|
||||
<div class="psudoCode">
|
||||
<a>vertical_displacement = points[0].y + points[1].y / 2;</a><br>
|
||||
<a>vertical_displacement *= 2 ** (-roughness);</a>
|
||||
</div>
|
||||
|
||||
<p>The top formula is the inital value. The second is applied very
|
||||
iteration of the sketch.</p>
|
||||
<p>Right now we can add one point to the list, time to add several! This
|
||||
means for loops. But before we can loop through our array how do we
|
||||
know which point should connect to which? We need to sort the array
|
||||
based on x value, so that the points read off from left to right.
|
||||
</p>
|
||||
<p>I just used a bubble sort for simplicity however it's worth pointing
|
||||
out that the number of points grows exponetially - <a>O(2^n)</a>
|
||||
where n = iterations - so after just 10 iterations <a>points.length
|
||||
= 1024</a>. A merge sort could be used to speed up computation
|
||||
times.</p>
|
||||
<p>Now we can use a for loop to go through our array and compare the ith
|
||||
item to the (i+1)th item, and then update <a>iterations</a> and
|
||||
<a>vertical_displacement</a>.
|
||||
</p>
|
||||
|
||||
<div class="psudoCode">
|
||||
<a>var pLength = points.length;</a><br><br>
|
||||
|
||||
<a> for (var i = 0; i < pLength - 1; i++){</a><br>
|
||||
|
||||
<a> var midX = (points[i].x + points[i +
|
||||
1].x) / 2;</a><br>
|
||||
<a> var midY = (points[i].y + points[i +
|
||||
1].y) / 2;</a><br>
|
||||
<a> midY += random(-vertical_displacement,
|
||||
vertical_displacement);</a><br>
|
||||
|
||||
<a> points[pLength + i] = new point(midX,
|
||||
midY);</a><br>
|
||||
<a> }</a><br><br>
|
||||
|
||||
<a>iterations += 1;</a><br>
|
||||
<a>vertical_displacement *= 2 ** (-roughness);</a><br>
|
||||
|
||||
<a>bubbleSort();</a><br>
|
||||
</div>
|
||||
<h2>NOTE: Do not use points.length to define your for loop as we are
|
||||
increasing the length of the array within the loop</h2>
|
||||
<!--<span id="c1"></span>-->
|
||||
</body>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.2.0/p5.min.js"
|
||||
integrity="sha512-b/htz6gIyFi3dwSoZ0Uv3cuv3Ony7EeKkacgrcVg8CMzu90n777qveu0PBcbZUA7TzyENGtU+qZRuFAkfqgyoQ=="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="sketch.js"></script>
|
||||
<script src="dot.js"></script>
|
||||
|
||||
|
||||
</html>
|
||||
90
tutorials/terrainGen/sketch.js
Normal file
90
tutorials/terrainGen/sketch.js
Normal file
@@ -0,0 +1,90 @@
|
||||
var MidDisplacement = function( p ){
|
||||
|
||||
var points = [];
|
||||
var iterations = 1;
|
||||
const roughness = 1;
|
||||
var vertical_displacement;
|
||||
let button;
|
||||
|
||||
p.setup = function(){
|
||||
p.createCanvas(800, 500);
|
||||
p.frameRate(2);
|
||||
p.background(217);
|
||||
|
||||
button = p.createButton('Reset Button')
|
||||
//button.position(p.width, p.height);
|
||||
button.mousePressed(p.resetSketch);
|
||||
p.initValues();
|
||||
|
||||
}
|
||||
|
||||
p.draw = function(){}
|
||||
|
||||
p.bubbleSort = function() {
|
||||
var length = points.length;
|
||||
//Number of passes
|
||||
for (var i = 0; i < length; i++) {
|
||||
//Notice that j < (length - i)
|
||||
for (var j = 0; j < (length - i - 1); j++) {
|
||||
//Compare the x values
|
||||
if(points[j].x > points[j+1].x) {
|
||||
//Swap the numbers
|
||||
var tmp = points[j]; //Temporary variable to hold the current number
|
||||
points[j] = points[j+1]; //Replace current number with adjacent number
|
||||
points[j+1] = tmp; //Replace adjacent number with current number
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p.mouseClicked = function(){
|
||||
if (iterations < 11){
|
||||
var pLength = points.length;
|
||||
|
||||
for (var i = 0; i < pLength - 1; i++){
|
||||
|
||||
var midX = (points[i].x + points[i + 1].x) / 2;
|
||||
var midY = (points[i].y + points[i + 1].y) / 2;
|
||||
midY += p.random(-vertical_displacement, vertical_displacement);
|
||||
|
||||
points[pLength + i] = new dot(midX, midY);
|
||||
}
|
||||
|
||||
iterations += 1;
|
||||
vertical_displacement *= 2 ** (-roughness);
|
||||
|
||||
p.bubbleSort();
|
||||
|
||||
p.clear();
|
||||
p.background(215);
|
||||
|
||||
for (var i = 0; i < pLength; i++){
|
||||
p.strokeWeight(4);
|
||||
p.stroke(0);
|
||||
p.point(points[i].x * 2, points[i].y);
|
||||
|
||||
p.strokeWeight(1);
|
||||
p.stroke(215, 15, 15);
|
||||
p.line(points[i].x * 2, points[i].y, points[i+1].x * 2, points[i+1].y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p.initValues = function(){
|
||||
points[0] = new dot(0, p.height/2);
|
||||
points[1] = new dot(p.width, p.height/2);
|
||||
|
||||
vertical_displacement = points[0].y + points[1].y / 2;
|
||||
vertical_displacement *= 2 ** (-roughness);
|
||||
|
||||
iterations = 1;
|
||||
}
|
||||
|
||||
p.resetSketch = function(){
|
||||
points.length = 0;
|
||||
p.clear()
|
||||
p.background(217);
|
||||
p.initValues();
|
||||
}
|
||||
};
|
||||
var myp5 = new p5(MidDisplacement, 'c1');
|
||||
71
tutorials/terrainGen/style.css
Normal file
71
tutorials/terrainGen/style.css
Normal file
@@ -0,0 +1,71 @@
|
||||
h1{
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
margin: 0;
|
||||
padding: 0 0 15px 0;
|
||||
font-weight: 700;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
h2{
|
||||
font-family: 'Roboto Condensed', sans-serif;
|
||||
margin: 0;
|
||||
padding: 15px 0 15px 0;
|
||||
font-weight: 650;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
p{
|
||||
margin: 1px;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 19px;
|
||||
padding: 5px 0px 5px 0px;
|
||||
}
|
||||
|
||||
.psudoCode{
|
||||
font-family: 'Inconsolata', monospace;
|
||||
font-size: 19px;
|
||||
background-color: #D9D9D9;
|
||||
border: 1px solid;
|
||||
padding: 5px;
|
||||
box-shadow: 5px 5px #888888;
|
||||
}
|
||||
|
||||
a{
|
||||
font-family: 'Inconsolata', monospace;
|
||||
font-size: 19px;
|
||||
background-color: #D9D9D9;
|
||||
|
||||
}
|
||||
|
||||
button{
|
||||
background-color: white;
|
||||
border: 2px solid #555555;
|
||||
color: black;
|
||||
padding: 16px 32px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 4px 2px;
|
||||
-webkit-transition-duration: 0.4s; /* Safari */
|
||||
transition-duration: 0.4s;
|
||||
cursor: pointer;
|
||||
float:right;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: #555555;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.examples{
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
|
||||
html{
|
||||
-webkit-user-select: none; /* Safari */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE10+/Edge */
|
||||
user-select: none; /* Standard */
|
||||
}
|
||||
Reference in New Issue
Block a user