Experiment with biomes

This commit is contained in:
Tim 2023-06-05 02:54:54 +02:00
parent cccd74f1a5
commit 007a9f7989
5 changed files with 65 additions and 24 deletions

View File

@ -18,15 +18,13 @@ class MapGenerator
$this->noise = new Noise($seed); $this->noise = new Noise($seed);
} }
public function getPixels(): array public function getPixels(): iterable
{ {
$pixels = [];
for ($x = 0; $x < $this->width; $x++) { for ($x = 0; $x < $this->width; $x++) {
for ($y = 0; $y < $this->height; $y++) { for ($y = 0; $y < $this->height; $y++) {
$pixels[] = $this->drawPixel($x, $y, $this->noise->generate($x, $y)); yield $this->drawPixel($x, $y, $this->noise->generate($x, $y));
} }
} }
return $pixels;
} }
private function drawPixel(int $x, int $y, Color $color): string private function drawPixel(int $x, int $y, Color $color): string

View File

@ -6,18 +6,20 @@ use Ardent\Game\dto\Color;
class Noise class Noise
{ {
private readonly PerlinNoise $noise; private readonly PerlinNoise $height;
private readonly PerlinNoise $biome;
public function __construct( public function __construct(
?int $seed = null, ?int $seed = null,
) )
{ {
$this->noise = new PerlinNoise($seed); $this->height = new PerlinNoise($seed);
$this->biome = new PerlinNoise($seed + 1);
} }
private function getTransitions(): array private function getGrassland(): array
{ {
$deepwater = new Color('#006eb4'); $deepwater = new Color(0, 110, 180);
$water = new Color(0, 156, 244); $water = new Color(0, 156, 244);
$sand = new Color(238, 226, 104); $sand = new Color(238, 226, 104);
$grass = new Color(25, 171, 64); $grass = new Color(25, 171, 64);
@ -26,7 +28,7 @@ class Noise
return [ return [
[-1.0, $deepwater], [-1.0, $deepwater],
[-0.9, $water], [-0.997, $water],
[0.0, $sand], [0.0, $sand],
[0.8, $grass], [0.8, $grass],
[0.997, $mountain], [0.997, $mountain],
@ -34,22 +36,46 @@ class Noise
]; ];
} }
private function getDesert(): array
{
$lightSand = new Color(248, 255, 111);
$sand = new Color(238, 226, 104);
$darkSand = new Color(161, 153, 70);
return [
[-1.0, $sand],
[1.0, $darkSand],
];
}
public function generate(int $x, int $y): Color public function generate(int $x, int $y): Color
{ {
$rand = $this->noise->random2D($x, $y, 150); $height = $this->height->random2D($x, $y, 150);
$transitions = $this->getTransitions();
for ($i = 0; $i < count($transitions) - 1; $i++) { // $biomes = [
$transition = $transitions[$i]; // [-1.0, $this->transitionTerrain($this->getGrassland(), $height)],
$nextTransition = $transitions[$i + 1]; // [1.01, $this->transitionTerrain($this->getDesert(), $height)],
if ($rand >= $transition[0] && $rand < $nextTransition[0]) { // ];
return $this->lerpTerrain($transition[1], $nextTransition[1], $transition[0], $nextTransition[0], $rand); // $biome = $this->biome->random2D($x, $y, 200, 5);
}
} return $this->transitionTerrain($this->getGrassland(), $height);
} }
public function lerpTerrain(Color $color1, Color $color2, float $begin, float $end, float $value): Color public function lerpTerrain(Color $color1, Color $color2, float $begin, float $end, float $value): Color
{ {
return $color1->lerp($color2, ($value - $begin) * (1.0 / ($end - $begin))); return $color1->lerp($color2, ($value - $begin) * (1.0 / ($end - $begin)));
} }
public function transitionTerrain(array $transitions, float $height): Color
{
$color = new Color('#000000');
for ($i = 0; $i < count($transitions) - 1; $i++) {
$transition = $transitions[$i];
$nextTransition = $transitions[$i + 1];
if ($height >= $transition[0] && $height < $nextTransition[0]) {
$color = $this->lerpTerrain($transition[1], $nextTransition[1], $transition[0], $nextTransition[0], $height);
}
}
return $color;
}
} }

View File

@ -148,7 +148,7 @@ class PerlinNoise
return $value; return $value;
} }
function random2D(float $x, float $y, ?int $size = NULL): float function random2D(float $x, float $y, ?int $size = null, float $multiplier = 1.0): float
{ {
if ($size === NULL) { if ($size === NULL) {
$size = $this->_default_size; $size = $this->_default_size;
@ -167,7 +167,7 @@ class PerlinNoise
// $value /= 2.0; // $value /= 2.0;
return $this->sigmoid($value); return $this->sigmoid($value * $multiplier);
} }
private function sigmoid(float $t): float private function sigmoid(float $t): float

View File

@ -5,14 +5,14 @@ namespace Ardent\Game\dto;
class Color class Color
{ {
public function __construct( public function __construct(
private int|string $red, private int|string $red,
private int $green = 0, private int $green = 0,
private int $blue = 0, private int $blue = 0,
private readonly int $alpha = 255 private readonly int $alpha = 255
) )
{ {
if (is_string($red)) { if (is_string($red)) {
list($this->red, $this->green, $this->blue) = sscanf($this->red, "#%02x%02x%02x"); [$this->red, $this->green, $this->blue] = sscanf($this->red, "#%02x%02x%02x");
} }
} }
@ -31,4 +31,19 @@ class Color
alpha: $this->alpha + ($color->alpha - $this->alpha) * $range, alpha: $this->alpha + ($color->alpha - $this->alpha) * $range,
); );
} }
public function brighten(float $amount): Color
{
return new Color(
red: $this->clamp($this->red + $amount, 0, 255),
green: $this->clamp($this->green + $amount, 0, 255),
blue: $this->clamp($this->blue + $amount, 0, 255),
alpha: $this->alpha,
);
}
private function clamp(int $current, int $min, int $max): int
{
return max($min, min($max, $current));
}
} }

View File

@ -9,6 +9,8 @@ include "MapGenerator.php";
$renderer = new Renderer(); $renderer = new Renderer();
$map = new MapGenerator($renderer, $_GET['seed'], (int)$_GET['width'], (int)$_GET['height']); $map = new MapGenerator($renderer, $_GET['seed'], (int)$_GET['width'], (int)$_GET['height']);
$start = microtime(true);
echo $renderer->render('map.html.twig', [ echo $renderer->render('map.html.twig', [
'map' => $map, 'map' => $map,
]); ]);
echo 'time: ' . microtime(true) - $start;