Better biome generation w/ temperature & humidity

This commit is contained in:
Namonay
2025-06-01 20:56:41 +02:00
parent 6bd1dd3a1b
commit 2e1bb94f82
4 changed files with 65 additions and 63 deletions

View File

@@ -2,6 +2,7 @@
#include "Biome.h" #include "Biome.h"
#include "Block.h" #include "Block.h"
#include "Chunk.h" #include "Chunk.h"
#include "NoiseCollection.h"
#include <utility> #include <utility>
Biome::Biome(std::uint32_t filler, std::uint32_t water_level, std::map<std::uint32_t, std::pair<BlockPlacementType, std::vector<BlockType>>> blocks): filler(filler), water_level(water_level), c_blockmap(blocks) Biome::Biome(std::uint32_t filler, std::uint32_t water_level, std::map<std::uint32_t, std::pair<BlockPlacementType, std::vector<BlockType>>> blocks): filler(filler), water_level(water_level), c_blockmap(blocks)
@@ -18,11 +19,14 @@ const std::array<std::uint32_t, CHUNK_SIZE.y> Biome::GetBiomeBlocks(const std::u
{ {
std::array<std::uint32_t, CHUNK_SIZE.y> data; std::array<std::uint32_t, CHUNK_SIZE.y> data;
auto it = c_blockmap.lower_bound(height); std::memset(data.data(), static_cast<std::uint32_t>(BlockType::Air), data.size() * sizeof(std::uint32_t));
std::fill(data.begin(), data.begin() + ARTIFICIAL_ELEVATION, filler);
std::fill(data.begin() + ARTIFICIAL_ELEVATION, data.begin() + ARTIFICIAL_ELEVATION + water_level, static_cast<std::uint32_t>(BlockType::Water));
auto it = c_blockmap.lower_bound(height - ARTIFICIAL_ELEVATION);
if (it == c_blockmap.end()) if (it == c_blockmap.end())
Scop::FatalError("Biome declaration does not have a value for a certain generated height"); Scop::FatalError("Biome declaration does not have a value for a certain generated height");
for(std::uint32_t y = 0; y < std::min(height, CHUNK_SIZE.y); y++) for(std::uint32_t y = ARTIFICIAL_ELEVATION; y < std::min(height, CHUNK_SIZE.y); y++)
{ {
if(y > std::min(height, CHUNK_SIZE.y) - 2) if(y > std::min(height, CHUNK_SIZE.y) - 2)
{ {
@@ -31,7 +35,7 @@ const std::array<std::uint32_t, CHUNK_SIZE.y> Biome::GetBiomeBlocks(const std::u
{ {
case(static_cast<std::uint8_t>(BlockPlacementType::Simple)): case(static_cast<std::uint8_t>(BlockPlacementType::Simple)):
{ {
data[y] = static_cast<std::uint32_t>(blockTypes.front()); data[y] = static_cast<std::uint32_t>(blockTypes.at(0));
break; break;
} }
case(static_cast<std::uint8_t>(BlockPlacementType::PseudoRandom)): case(static_cast<std::uint8_t>(BlockPlacementType::PseudoRandom)):
@@ -44,7 +48,7 @@ const std::array<std::uint32_t, CHUNK_SIZE.y> Biome::GetBiomeBlocks(const std::u
break; break;
} }
default: default:
data[y] = static_cast<std::uint32_t>(BlockType::Stone); data[y] = static_cast<std::uint32_t>(BlockType::Stone); // fallback
} }
} }
else else
@@ -52,10 +56,5 @@ const std::array<std::uint32_t, CHUNK_SIZE.y> Biome::GetBiomeBlocks(const std::u
data[y] = filler; data[y] = filler;
} }
} }
for(std::uint32_t y = 0; y < water_level; y++)
{
if(data[y] == static_cast<std::uint32_t>(BlockType::Air))
data[y] = static_cast<std::uint32_t>(BlockType::Water);
}
return data; return data;
} }

View File

@@ -6,6 +6,7 @@
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
#include "Biome.h" #include "Biome.h"
#include "Block.h"
#include "Chunk.h" #include "Chunk.h"
#include "Maths/Vec2.h" #include "Maths/Vec2.h"
@@ -15,13 +16,33 @@ class BiomeCollection
inline BiomeCollection() inline BiomeCollection()
{ {
m_collection.emplace("grassland", std::make_unique<Biome>( m_collection.emplace("grassland", std::make_unique<Biome>(
static_cast<std::uint32_t>(BlockType::Stone), static_cast<std::uint32_t>(BlockType::Stone),
0, 20,
{ std::map<std::uint32_t, std::pair<BlockPlacementType, std::vector<BlockType>>>{
{20, {BlockPlacementType::Simple, {BlockType::Sand}}}, {23, std::pair<BlockPlacementType, std::vector<BlockType>>{BlockPlacementType::Simple, std::vector<BlockType>{BlockType::Sand}}},
{255, {BlockPlacementType::Simple, {BlockType::Snow}}} {125, std::pair<BlockPlacementType, std::vector<BlockType>>{BlockPlacementType::Simple, std::vector<BlockType>{BlockType::Grass}}},
} {132, std::pair<BlockPlacementType, std::vector<BlockType>>{BlockPlacementType::PseudoRandom, std::vector<BlockType>{BlockType::SnowyGrass, BlockType::Grass}}},
)); {140, std::pair<BlockPlacementType, std::vector<BlockType>>{BlockPlacementType::PseudoRandom, std::vector<BlockType>{BlockType::Snow, BlockType::SnowyGrass}}},
{255, std::pair<BlockPlacementType, std::vector<BlockType>>{BlockPlacementType::Simple, std::vector<BlockType>{BlockType::Snow}}}
}
));
m_collection.emplace("tundra", std::make_unique<Biome>(
static_cast<std::uint32_t>(BlockType::Stone),
20,
std::map<std::uint32_t, std::pair<BlockPlacementType, std::vector<BlockType>>>{
{23, std::pair<BlockPlacementType, std::vector<BlockType>>{BlockPlacementType::Simple, std::vector<BlockType>{BlockType::Snow}}},
{120, std::pair<BlockPlacementType, std::vector<BlockType>>{BlockPlacementType::Simple, std::vector<BlockType>{BlockType::SnowyGrass}}},
{140, std::pair<BlockPlacementType, std::vector<BlockType>>{BlockPlacementType::PseudoRandom, std::vector<BlockType>{BlockType::Snow, BlockType::SnowyGrass}}},
{255, std::pair<BlockPlacementType, std::vector<BlockType>>{BlockPlacementType::Simple, std::vector<BlockType>{BlockType::Snow}}}
}
));
m_collection.emplace("desert", std::make_unique<Biome>(
static_cast<std::uint32_t>(BlockType::Stone),
20,
std::map<std::uint32_t, std::pair<BlockPlacementType, std::vector<BlockType>>>{
{255, std::pair<BlockPlacementType, std::vector<BlockType>>{BlockPlacementType::Simple, std::vector<BlockType>{BlockType::Sand}}}
}
));
}; };
const std::array<std::uint32_t, CHUNK_SIZE.y> GetBiomeBlocks(std::string biome, std::uint32_t height, Scop::Vec2i pos) const; const std::array<std::uint32_t, CHUNK_SIZE.y> GetBiomeBlocks(std::string biome, std::uint32_t height, Scop::Vec2i pos) const;
~BiomeCollection() = default; ~BiomeCollection() = default;

View File

@@ -20,50 +20,14 @@ const std::array<std::uint32_t, CHUNK_SIZE.y> NoiseCollection::GetBlocks(Scop::V
{ {
const std::uint32_t height = m_collection["terrain"]->Perlin2D(pos.x, pos.y) + ARTIFICIAL_ELEVATION; const std::uint32_t height = m_collection["terrain"]->Perlin2D(pos.x, pos.y) + ARTIFICIAL_ELEVATION;
std::array<std::uint32_t, CHUNK_SIZE.y> data; std::array<std::uint32_t, CHUNK_SIZE.y> data;
std::memset(data.data(), static_cast<std::uint32_t>(BlockType::Air), data.size() * sizeof(std::uint32_t));
data = c_biomecollection.GetBiomeBlocks("grassland", height, pos);
return data;
for(std::uint32_t y = 0; y < std::min(height, CHUNK_SIZE.y); y++)
{
// const std::uint32_t value = Perlin3D(pos.x, y, pos.y);
if(y > std::min(height, CHUNK_SIZE.y) - 2)
{
if(height <= 23 + ARTIFICIAL_ELEVATION)
data[y] = static_cast<std::uint32_t>(BlockType::Sand);
else if(height < 125 + ARTIFICIAL_ELEVATION)
data[y] = static_cast<std::uint32_t>(BlockType::Grass);
else if (height < 132 + ARTIFICIAL_ELEVATION)
{
float weight = sin(2 * (pos.x * pos.y)) + sin(Scop::Pi<float>() * (pos.x * pos.y));
if (weight > 0.0f)
data[y] = static_cast<std::uint32_t>(BlockType::Grass);
else
data[y] = static_cast<std::uint32_t>(BlockType::SnowyGrass);
}
else if (height < 140 + ARTIFICIAL_ELEVATION)
{
float weight = sin(2 * (pos.x * pos.y)) + sin(Scop::Pi<float>() * (pos.x * pos.y));
if (weight > 0.0f)
data[y] = static_cast<std::uint32_t>(BlockType::Snow);
else
data[y] = static_cast<std::uint32_t>(BlockType::SnowyGrass);
}
else
data[y] = static_cast<std::uint32_t>(BlockType::Snow);
}
else
data[y] = static_cast<std::uint32_t>(BlockType::Stone);
}
for(std::uint32_t y = 0; y < ARTIFICIAL_ELEVATION + WATER_LEVEL; y++)
{
if(data[y] == static_cast<std::uint32_t>(BlockType::Air))
data[y] = static_cast<std::uint32_t>(BlockType::Water);
}
const std::uint32_t biome_value = m_collection["biomes"]->Perlin2D(pos.x, pos.y); const std::uint32_t biome_value = m_collection["biomes"]->Perlin2D(pos.x, pos.y);
const std::uint32_t temperature = m_collection["temperature"]->Perlin2D(pos.x, pos.y);
if (biome_value > 20) const std::uint32_t humidity = m_collection["humidity"]->Perlin2D(pos.x, pos.y);
data[240] = static_cast<std::uint32_t>(BlockType::Stone); if (temperature < 85 && humidity <= 110)
return data; return c_biomecollection.GetBiomeBlocks("tundra", height, pos);
if (temperature >= 85 && temperature <= 145 && humidity >= 85)
return c_biomecollection.GetBiomeBlocks("grassland", height, pos);
if (temperature >= 145)
return c_biomecollection.GetBiomeBlocks("desert", height, pos);
return c_biomecollection.GetBiomeBlocks("grassland", height, pos);
} }

View File

@@ -25,6 +25,15 @@ class NoiseCollection
4, 4,
1.2f 1.2f
)); ));
m_collection.emplace("humidity", std::make_unique<Noise>(seed, // seed
0.02f,
0.3f,
1,
2.0f,
0.6f,
2,
1.0f
));
m_collection.emplace("caves", std::make_unique<Noise>(seed, m_collection.emplace("caves", std::make_unique<Noise>(seed,
0.02f, 0.02f,
1.0f, 1.0f,
@@ -34,15 +43,24 @@ class NoiseCollection
3, 3,
1.0f 1.0f
)); // TODO !!!!!! )); // TODO !!!!!!
m_collection.emplace("biomes", std::make_unique<Noise>(seed, m_collection.emplace("biomes", std::make_unique<Noise>(seed + 1,
0.05f, 0.05f,
1.0f, 0.1f,
1, 1,
2.0f, 2.0f,
0.5f, 0.5f,
1, 1,
1.0f 1.0f
)); ));
m_collection.emplace("temperature", std::make_unique<Noise>(seed + 1,
0.02f,
0.3f,
2,
2.0f,
0.55f,
2,
1.05f
));
} }
Noise* GetNoise(const std::string& key) const; Noise* GetNoise(const std::string& key) const;