summary refs log tree commit diff
path: root/src/World/Generator.cpp
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-10-31 06:24:34 +0100
committerMel <einebeere@gmail.com>2022-10-31 06:24:34 +0100
commit23b0bc4d1ddc9fad3c32e8257497ddd13ac6a155 (patch)
tree16ac3e0fa2964f026c857daa4ff6f0ca11520d46 /src/World/Generator.cpp
parent1b2b0069c9b7ad73c6cc6663b020d0fd894f4567 (diff)
downloadmeowcraft-23b0bc4d1ddc9fad3c32e8257497ddd13ac6a155.tar.zst
meowcraft-23b0bc4d1ddc9fad3c32e8257497ddd13ac6a155.zip
Proto biomes and new blocks
Diffstat (limited to 'src/World/Generator.cpp')
-rw-r--r--src/World/Generator.cpp178
1 files changed, 166 insertions, 12 deletions
diff --git a/src/World/Generator.cpp b/src/World/Generator.cpp
index ee7ece9..875a79b 100644
--- a/src/World/Generator.cpp
+++ b/src/World/Generator.cpp
@@ -6,23 +6,46 @@ namespace MC::World {
 Chunk Generator::generate(int64_t chunk_x, int64_t chunk_y) {
     Chunk chunk(chunk_x, chunk_y);
 
-    uint8_t extent = 60;
-    uint8_t base = 4;
+    auto ocean_weights = ocean_weights_pass(chunk_x, chunk_y);
+    auto biome_weights = biome_weights_pass(chunk_x, chunk_y, ocean_weights);
+    auto heights = height_pass(chunk_x, chunk_y, biome_weights);
+    auto biomes = flat_biome_pass(biome_weights);
 
-    for (int x = 0; x < CHUNK_WIDTH; x++) {
-        for (int z = 0; z < CHUNK_WIDTH; z++) {
-            float noise = Math::noise2d(
-                {(float)chunk_x * CHUNK_WIDTH + x, (float)chunk_y * CHUNK_WIDTH + z}
-            ) * extent + base;
+    float extent = 60.0f;
+    float base = 4.0f;
 
-            uint height = std::round(noise);
+    for (int x = 0; x < Chunk::Width; x++) {
+        for (int z = 0; z < Chunk::Width; z++) {
+            uint32_t height = std::round(heights(x, z) * extent + base);
 
-            for (int y = 0; y < CHUNK_HEIGHT; y++) {
+            auto biome = biomes(x, z);
+
+            BlockType top_block{};
+            BlockType fill_block{};
+            switch (biome) {
+                case BiomeType::Forest:
+                case BiomeType::Plains:
+                    top_block = BlockType::Grass;
+                    fill_block = BlockType::Dirt;
+                    break;
+                case BiomeType::Desert:
+                    top_block = BlockType::Sand;
+                    fill_block = BlockType::Sand;
+                    break;
+                case BiomeType::Ocean:
+                    top_block = BlockType::Water;
+                    fill_block = BlockType::Dirt;
+                    break;
+            }
+
+            for (int y = 0; y < Chunk::Height; y++) {
                 BlockType type = BlockType::Air;
-                if (y < height) {
-                    type = BlockType::Dirt;
+                if (y < (int32_t)height - 10) {
+                    type = BlockType::Stone;
+                } else if (y < height) {
+                    type = fill_block;
                 } else if (y == height) {
-                    type = BlockType::Grass;
+                    type = top_block;
                 }
 
                 chunk.set(x, y, z, type);
@@ -33,4 +56,135 @@ Chunk Generator::generate(int64_t chunk_x, int64_t chunk_y) {
     return chunk;
 }
 
+Matrix<Chunk::Width, Chunk::Width> Generator::ocean_weights_pass(int64_t chunk_x, int64_t chunk_y) {
+    auto ocean_offset = 1125.0f;
+    auto ocean_scale = 0.05f;
+
+    Matrix<Chunk::Width, Chunk::Width> ocean_weights{};
+    for (int x = 0; x < Chunk::Width; x++) {
+        for (int y = 0; y < Chunk::Width; y++) {
+            float ocean_weight = Math::noise2d({
+                (chunk_x * Chunk::Width + x) * ocean_scale + ocean_offset,
+                (chunk_y * Chunk::Width + y) * ocean_scale + ocean_offset
+            });
+
+            ocean_weights(x, y) = ocean_weight;
+        }
+    }
+
+    return ocean_weights;
+}
+
+Matrix<Chunk::Width, Chunk::Width, Vector<BiomeType::Size>> Generator::biome_weights_pass(
+    int64_t chunk_x,
+    int64_t chunk_y,
+    Matrix<Chunk::Width, Chunk::Width, float> ocean_weights
+) {
+    auto ocean_threshold = 0.4f;
+
+    std::vector<float> biome_offsets = {110.0f, 2450.0f, 5042.0f};
+    auto biome_scale = 0.15f;
+
+    Matrix<Chunk::Width, Chunk::Width, Vector<BiomeType::Size>> biome_weights{};
+    for (int x = 0; x < Chunk::Width; x++) {
+        for (int y = 0; y < Chunk::Width; y++) {
+            Vector<BiomeType::Size> weights{};
+            for (auto biome : MC::World::BiomeType::all_ground()) {
+                float biome_noise = Math::noise2d({
+                    (chunk_x * Chunk::Width + x) * biome_scale + biome_offsets[biome],
+                    (chunk_y * Chunk::Width + y) * biome_scale + biome_offsets[biome]
+                });
+
+                weights[biome] = biome_noise;
+            }
+
+            bool ocean_weight = ocean_weights(x, y) < ocean_threshold;
+            weights[MC::World::BiomeType::Ocean] = ocean_weight;
+
+            biome_weights(x,y) = weights;
+        }
+    }
+
+    return biome_weights;
+}
+
+Matrix<Chunk::Width, Chunk::Width> Generator::height_pass(
+    int64_t chunk_x,
+    int64_t chunk_y,
+    Matrix<Chunk::Width, Chunk::Width, Vector<BiomeType::Size>> biome_weights
+) {
+    auto height_offset = 6050.0f;
+    auto height_scale = 0.7f;
+
+    Matrix<Chunk::Width, Chunk::Width> heights{};
+    for (int x = 0; x < Chunk::Width; x++) {
+        for (int y = 0; y < Chunk::Width; y++) {
+            auto weights = biome_weights(x, y);
+
+            auto total_weight = 0.0f;
+            for (auto biome : MC::World::BiomeType::all()) {
+                total_weight += weights[biome];
+            }
+
+            std::pair<float, float> total_effect{};
+            for (auto biome : MC::World::BiomeType::all()) {
+                auto weight = weights[biome];
+
+                std::pair<float, float> effect{};
+                switch (biome) {
+                    case MC::World::BiomeType::Forest:
+                        effect = {0.5f, 0.45f};
+                        break;
+                    case MC::World::BiomeType::Plains:
+                        effect = {0.4f, 0.4f};
+                        break;
+                    case MC::World::BiomeType::Desert:
+                        effect = {0.6f, 0.35f};
+                        break;
+                    case MC::World::BiomeType::Ocean:
+                        effect = {0.0f, 0.0f};
+                        break;
+                }
+
+                total_effect = {
+                    total_effect.first + effect.first * (weight / total_weight),
+                    total_effect.second + effect.second * (weight / total_weight),
+                };
+            }
+
+            float height = Math::noise2d({
+                (chunk_x * Chunk::Width + x) * height_scale + height_offset,
+                (chunk_y * Chunk::Width + y) * height_scale + height_offset
+            }) * total_effect.first + total_effect.second;
+
+            heights(x, y) = height;
+        }
+    }
+
+    return heights;
+}
+
+Matrix<Chunk::Width, Chunk::Width, BiomeType> Generator::flat_biome_pass(
+    Matrix<Chunk::Width, Chunk::Width, Vector<BiomeType::Size>> biome_weights
+) {
+    Matrix<Chunk::Width, Chunk::Width, BiomeType>  biomes{};
+    for (int x = 0; x < Chunk::Width; x++) {
+        for (int y = 0; y < Chunk::Width; y++) {
+            auto weights = biome_weights(x, y);
+
+            std::pair<MC::World::BiomeType, float> max_biome{MC::World::BiomeType::Plains, 0.0f};
+            for (auto biome : MC::World::BiomeType::all()) {
+                auto weight = weights[biome];
+                if (weight > max_biome.second) {
+                    max_biome = {biome, weight};
+                }
+            }
+
+            biomes(x, y) = max_biome.first;
+        }
+    }
+
+    return biomes;
+}
+
 }
\ No newline at end of file