Skip to content

Instantly share code, notes, and snippets.

@decima
Last active November 16, 2017 22:44
Show Gist options
  • Save decima/996816b7984b6eeddc5f6a5ced0502af to your computer and use it in GitHub Desktop.
Save decima/996816b7984b6eeddc5f6a5ced0502af to your computer and use it in GitHub Desktop.
Perlin script
<?php
set_time_limit(0);
//This is a port of Ken Perlin's "Improved Noise"
// http://mrl.nyu.edu/~perlin/noise/
// Originally from http://therandomuniverse.blogspot.com/2007/01/perlin-noise-your-new-best-friend.html
// but the site appears to be down, so here is a mirror of it
class Perlin
{
var $p, $permutation, $seed;
var $_default_size = 64;
function Perlin($seed = NULL)
{
//Initialize the permutation array.
$this->p = array();
$this->permutation = array(151, 160, 137, 91, 90, 15,
131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23,
190, 6, 148, 247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33,
88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, 134, 139, 48, 27, 166,
77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244,
102, 143, 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196,
135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64, 52, 217, 226, 250, 124, 123,
5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42,
223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228,
251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107,
49, 192, 214, 31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254,
138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180
);
//Populate it
for ($i = 0; $i < 256; $i++) {
$this->p[256 + $i] = $this->p[$i] = $this->permutation[$i];
}
//And set the seed
if ($seed === NULL) $this->seed = time();
else $this->seed = $seed;
}
function noise($x, $y, $z, $size = NULL)
{
if ($size == NULL) $size = $this->_default_size;
//Set the initial value and initial size
$value = 0.0;
$initialSize = $size;
//Add finer and finer hues of smoothed noise together
while ($size >= 1) {
$value += $this->smoothNoise($x / $size, $y / $size, $z / $size) * $size;
$size /= 2.0;
}
//Return the result over the initial size
return $value / $initialSize;
}
//This function determines what cube the point passed resides in
//and determines its value.
function smoothNoise($x, $y, $z)
{
//Offset each coordinate by the seed value
$x += $this->seed;
$y += $this->seed;
$z += $this->seed;
$orig_x = $x;
$orig_y = $y;
$orig_z = $z;
$X1 = (int)floor($x) & 255; // FIND UNIT CUBE THAT
$Y1 = (int)floor($y) & 255; // CONTAINS POINT.
$Z1 = (int)floor($z) & 255;
$x -= floor($x); // FIND RELATIVE X,Y,Z
$y -= floor($y); // OF POINT IN CUBE.
$z -= floor($z);
$u = $this->fade($x); // COMPUTE FADE CURVES
$v = $this->fade($y); // FOR EACH OF X,Y,Z.
$w = $this->fade($z);
$A = $this->p[$X1] + $Y1;
$AA = $this->p[$A] + $Z1;
$AB = $this->p[$A + 1] + $Z1; // HASH COORDINATES OF
$B = $this->p[$X1 + 1] + $Y1;
$BA = $this->p[$B] + $Z1;
$BB = $this->p[$B + 1] + $Z1; // THE 8 CUBE CORNERS,
//Interpolate between the 8 points determined
$result = $this->lerp($w, $this->lerp($v, $this->lerp($u, $this->grad($this->p[$AA], $x, $y, $z), // AND ADD
$this->grad($this->p[$BA], $x - 1, $y, $z)), // BLENDED
$this->lerp($u, $this->grad($this->p[$AB], $x, $y - 1, $z), // RESULTS
$this->grad($this->p[$BB], $x - 1, $y - 1, $z))),// FROM 8
$this->lerp($v, $this->lerp($u, $this->grad($this->p[$AA + 1], $x, $y, $z - 1), // CORNERS
$this->grad($this->p[$BA + 1], $x - 1, $y, $z - 1)), // OF CUBE
$this->lerp($u, $this->grad($this->p[$AB + 1], $x, $y - 1, $z - 1),
$this->grad($this->p[$BB + 1], $x - 1, $y - 1, $z - 1))));
return $result;
}
function fade($t)
{
return $t * $t * $t * (($t * (($t * 6) - 15)) + 10);
}
function lerp($t, $a, $b)
{
//Make a weighted interpolaton between points
return $a + $t * ($b - $a);
}
function grad($hash, $x, $y, $z)
{
$h = $hash & 15; // CONVERT LO 4 BITS OF HASH CODE
$u = $h < 8 ? $x : $y; // INTO 12 GRADIENT DIRECTIONS.
$v = $h < 4 ? $y : ($h == 12 || $h == 14 ? $x : $z);
return (($h & 1) == 0 ? $u : -$u) + (($h & 2) == 0 ? $v : -$v);
}
}
$biomes = [
0 => ["deepocean", "deepocean", "deepocean", "deepocean", "deepocean", "deepocean"],
1 => ["deepocean", "ocean", "ocean", "ocean", "ocean", "ocean"],
1 => ["ocean", "ocean", "ocean", "ocean", "ocean", "lake"],
2 => ["lake", "lake", "desert", "grassland", "forest", "forest"],
3 => ["lake", "grassland", "grassland", "forest", "forest", "stone"],
4 => ["stone", "stone", "stone", "snow", "snow", "snow",],
];
$seed = 338403732;
//$seed = 1510868393;
//$seed = 1510868812;
$baseX = -100;
$baseY = -100;
if (isset($_GET["x"])) {
$baseX = $_GET["x"];
}
if (isset($_GET["y"])) {
$baseY = $_GET["y"];
}
$bob = new Perlin($seed);
$john = new Perlin($seed * 1.5);
$coastLeft = new Perlin($seed * 2);
$coastRight = new Perlin($seed * 6);
$coastTop = new Perlin($seed * 4);
$coastBottom = new Perlin($seed * 10);
$size = 1;
$smooth = 20;
$height = 200;
$width = 200;
$heightLimit = $baseY + $height;
$widthLimit = $baseX + $width;
$maxHeight = 5;
$maxDry = 5;
$map = [];
for ($y = $baseY; $y < $heightLimit; $y++) {
$map[$y] = [];
for ($x = $baseX; $x < $widthLimit; $x++) {
$hu = round(($john->noise($x, $y, 0, $smooth) + 1) * 0.5 * $maxDry);
$he = round(($bob->noise($x, $y, 0, $smooth) + 1) * 0.5 * $maxHeight);
$biome = $biomes[$he][$hu];
$map[$y][$x] = [
"height" => $he,
"humidity" => $hu,
"biome" => $biome,
];
}
}
$topCoast = [];
$bottomCoast = [];
for ($i = $baseX; $i < $baseX + $width; $i++) {
$val = round(($coastTop->noise($i, 0, 0.1) + 1) * 0.5 * 100) - 40;
$coast = round(($coastTop->noise(0, $i, 1) + 1) * 0.5 * 15);
for ($j = 0; $j < $val; $j++) {
$map[$baseY + $j][$i]["biome"] = "ocean";
if ($j >= $coast) {
$map[$baseY + $j][$i]["biome"] = "lake";
}
}
$val = round(($coastBottom->noise($i, 0, 0.1) + 1) * 0.5 * 100) - 40;
$coast = round(($coastBottom->noise(0, $i, 1) + 1) * 0.5 * 15);
for ($j = 0; $j < $val; $j++) {
$map[$baseY + $height - $j][$i]["biome"] = "ocean";
if ($j >= $coast) {
$map[$baseY + $height - $j][$i]["biome"] = "lake";
}
}
}
for ($i = $baseY; $i < $baseY + $height; $i++) {
$val = round(($coastLeft->noise($i, 0, 0.1) + 1) * 0.5 * 100) - 40;
$coast = round(($coastLeft->noise($i, 1, 0.1) + 1) * 0.5 * 70) - 30;
for ($j = 0; $j < $val; $j++) {
$map[$i][$baseX + $j]["biome"] = "ocean";
if ($j >= $coast) {
$map[$i][$baseX + $j]["biome"] = "lake";
}
}
$val = round(($coastRight->noise($i, 0, 0.1) + 1) * 0.5 * 100) - 40;
$coast = round(($coastRight->noise($i, 1, 1) + 1) * 0.5 * 70) - 30;
for ($j = 0; $j < $val; $j++) {
$map[$i][$baseX + $width - $j]["biome"] = "ocean";
if ($j >= $coast) {
$map[$i][$baseX + $width - $j]["biome"] = "lake";
}
}
}
$mapColor = [
"deepocean" => "0D47A1",
"ocean" => "2196F3",
"lake" => "64B5F6",
"desert" => "FDD835",
"grassland" => "8BC34A",
"tropical" => "AFB42B",
"forest" => "33691E",
"temperate" => "D4E157",
"taiga" => "A1887F",
"stone" => "9E9E9E",
"snow" => "F5F5F5"
];
?>
<!doctype HTML>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>map</title>
<style>
table {
border-collapse: collapse;
}
td {
width: 6px;
height: 6px;
}
<?php foreach($mapColor as $k=>$v):?>
<?=".".$k;?>
{
background-color:
<?= "#".$v;?>
;
}
<?php endforeach;?>
.wrapper {
display: flex;
flex-direction: row;
}
.row {
flex: 1 1 auto;
}
.player {
width: 80%;
height: 80%;
margin: 10%;
background-color: rgba(255, 0, 0, 1);
border-radius: 100%;
}
.controller td {
width: 100px;
height: 100px;
}
a {
font-size: 5em;
text-decoration: none;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="row">
<table>
<?php foreach ($map as $r => $row): ?>
<tr>
<?php foreach ($row as $c => $cell): ?>
<td class="<?= $cell["biome"]; ?>">
<?php if (0 == $r): ?>
<?php if (0 == $c): ?>
<div class="player"></div>
<?php endif; ?>
<?php endif; ?>
<?php if (false && round($baseY + $height / 2, 0, PHP_ROUND_HALF_DOWN) == $r): ?>
<?php if (false && round($baseX + $width / 2, 0, PHP_ROUND_HALF_DOWN) == $c): ?>
<div class="player"></div>
<?php endif; ?>
<?php endif; ?>
</td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
<tr></tr>
</table>
</div>
<div class="row">
<table class="controller">
<tr>
<td><a href="?x=<?= $baseX - 1; ?>&y=<?= $baseY - 1; ?>">&#x1F87C;</a></td>
<td><a href="?x=<?= $baseX; ?>&y=<?= $baseY - 1; ?>">&#x2bc5;</a></td>
<td><a href="?x=<?= $baseX + 1; ?>&y=<?= $baseY - 1; ?>">&#x1F87D;</a></td>
</tr>
<tr>
<td><a href="?x=<?= $baseX - 1; ?>&y=<?= $baseY; ?>">&#x2bc7;</a></td>
<td></td>
<td><a href="?x=<?= $baseX + 1; ?>&y=<?= $baseY; ?>">&#x2bc8;</a></td>
</tr>
<tr>
<td><a href="?x=<?= $baseX - 1; ?>&y=<?= $baseY + 1; ?>">&#x1F87F;</a></td>
<td><a href="?x=<?= $baseX; ?>&y=<?= $baseY + 1; ?>">&#x2bc6;</a></td>
<td><a href="?x=<?= $baseX + 1; ?>&y=<?= $baseY + 1; ?>">&#x1F87E;</a></td>
</tr>
</table>
</div>
</div>
<table>
<tr>
<th>Seed</th>
<td><?= $seed; ?></td>
</tr>
</table>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment