summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt7
-rw-r--r--src/Common/FlexArray.hpp85
-rw-r--r--src/Entities/Player.cpp17
-rw-r--r--src/Entities/Player.hpp4
-rw-r--r--src/World/Chunk.cpp15
-rw-r--r--src/World/Chunk.hpp6
-rw-r--r--src/World/Generation/Decoration.cpp6
-rw-r--r--src/World/Generation/Decoration.hpp2
8 files changed, 119 insertions, 23 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fc29dd3..421c006 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,10 +59,9 @@ add_executable(meowcraft
     src/World/Position.hpp
     src/World/ChunkDimensions.hpp
     src/Math/Mod.hpp
-    src/Transform.cpp
-    src/Transform.hpp
-    src/Entities/Player.cpp
-    src/Entities/Player.hpp
+    src/Transform.cpp src/Transform.hpp
+    src/Entities/Player.cpp src/Entities/Player.hpp
+    src/Common/FlexArray.hpp
 )
 target_link_libraries(meowcraft glfw GLEW::GLEW)
 
diff --git a/src/Common/FlexArray.hpp b/src/Common/FlexArray.hpp
new file mode 100644
index 0000000..4a648b6
--- /dev/null
+++ b/src/Common/FlexArray.hpp
@@ -0,0 +1,85 @@
+#pragma once
+
+#include <array>
+#include "Sizes.hpp"
+
+template <typename T, uint S>
+class FlexArray {
+public:
+    FlexArray() = default;
+
+    FlexArray& operator=(const FlexArray& other) {
+        m_count = other.m_count;
+        m_array = other.m_array;
+        return *this;
+    }
+
+    T& at(USize index) {
+        assure_in_bounds(index);
+        return m_array.at(index);
+    }
+    const T& at(USize index) const {
+        assure_in_bounds(index);
+        return m_array.at(index);
+    }
+
+    T& operator[](USize index) {
+        assure_in_bounds(index); // STL doesn't do bounds-checks here, and it led to many headaches :(
+        return m_array[index];
+    }
+    const T& operator[](USize index) const {
+        assure_in_bounds(index);
+        return m_array[index];
+    }
+
+    T& front() { return at(0); }
+    const T& front() const { return at(0); }
+
+    T& back() { return at(m_count - 1); }
+    const T& back() const { return at(m_count - 1); }
+
+    const T* data() const { return m_array.data(); }
+    T* data() { return m_array.data(); }
+
+    std::array<T, S>& array() { return m_array; }
+    const std::array<T, S>& array() const { return m_array; }
+
+    T* begin() { return m_array.begin(); }
+    T* end() { return m_array.begin() + m_count; }
+
+    Bool empty() const { return m_count == 0; }
+    Bool full() const { return m_count == S; }
+
+    USize size() const { return m_count; }
+    USize max_size() const { return S; }
+
+    void clear() { m_count = 0; m_array = {}; }
+
+    void push_back(const T& value) {
+        if (m_count >= S) throw std::out_of_range("flex array is full");
+        m_array[m_count] = value;
+        m_count++;
+    }
+
+    template <typename... Args>
+    void emplace_back(Args&&... args) {
+        if (full()) throw std::out_of_range("flex array is full");
+        m_array[m_count] = T{std::forward<Args>(args)...};
+        m_count++;
+    }
+
+    void pop_back() {
+        if (empty()) throw std::out_of_range("flex array is empty");
+        m_array[m_count - 1] = {};
+        m_count--;
+    }
+
+private:
+    void assure_in_bounds(USize index) const {
+        if (index >= m_count) throw std::out_of_range("flex array index out of range");
+    }
+
+    USize m_count = 0;
+    std::array<T, S> m_array{};
+};
+
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 175b59e..6c94490 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -18,7 +18,8 @@ void Player::update(const Time& time, GFX::Window& window, GFX::Camera& camera,
     auto direction = m_transform.right() * x + Vec3(0, y, 0) + m_transform.forward() * z;
     auto position = m_transform.position() + direction * move_speed;
 
-    if (!collides_with_terrain(position, world)) move_to(position);
+    auto collisions = colliding_terrain(position, world);
+    if (collisions.empty()) move_to(position);
     rotate({r.y() * rotation_speed, r.x() * rotation_speed, 0.0f});
 
     update_camera_position(camera);
@@ -53,18 +54,24 @@ void Player::update_camera_position(GFX::Camera& camera) {
     camera.set_angles(m_transform.rotation());
 }
 
-Bool Player::collides_with_terrain(Position::World new_position, World::World& world) {
-    auto corners = bounding_box_for_position(new_position).corners();
+FlexArray<AABB, Player::MaxCollidingTerrain> Player::colliding_terrain(
+    Position::World new_position,
+    World::World& world
+) {
+    FlexArray<AABB, MaxCollidingTerrain> colliding_blocks;
 
+    auto corners = bounding_box_for_position(new_position).corners();
     for (auto corner : corners) {
         auto block_position = Position::World(corner).round_to_block();
         if (block_position.y() < 0 || block_position.y() >= World::Chunk::Height) continue;
 
         auto block = world.block_at(block_position);
-        if (!block.empty()) return true;
+        if (!block.empty()) {
+            colliding_blocks.push_back(World::Chunk::block_bounds(block_position.to_local()));
+        }
     }
 
-    return false;
+    return colliding_blocks;
 }
 
 AABB Player::bounding_box_for_position(Position::World position) {
diff --git a/src/Entities/Player.hpp b/src/Entities/Player.hpp
index 86d8c90..0422509 100644
--- a/src/Entities/Player.hpp
+++ b/src/Entities/Player.hpp
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "../Common/FlexArray.hpp"
 #include "../Time.hpp"
 #include "../Transform.hpp"
 #include "../GFX/Camera.hpp"
@@ -27,7 +28,8 @@ public:
 private:
     void update_camera_position(GFX::Camera& camera);
 
-    static Bool collides_with_terrain(Position::World new_position, World::World& world);
+    static constexpr UInt MaxCollidingTerrain = 34;
+    static FlexArray<AABB, MaxCollidingTerrain> colliding_terrain(Position::World new_position, World::World& world);
 
     // Creates a bounding box where `position` is at the center of the bottom face.
     static AABB bounding_box_for_position(Position::World position);
diff --git a/src/World/Chunk.cpp b/src/World/Chunk.cpp
index 8b204c0..6cb67bb 100644
--- a/src/World/Chunk.cpp
+++ b/src/World/Chunk.cpp
@@ -19,10 +19,6 @@ Chunk::BlockData& Chunk::at(Position::BlockLocal pos) {
     return at(pos.x(), pos.y(), pos.z());
 }
 
-Bool Chunk::is_empty(U32 x, U32 y, U32 z) const {
-    return at(x, y, z).empty();
-}
-
 ChunkIndex Chunk::index() const {
     return m_index;
 }
@@ -39,12 +35,19 @@ void Chunk::damage() {
     m_damaged = true;
 }
 
-Bool Chunk::is_valid_position(U32 x, U32 y, U32 z) {
-    return x < Width && y < Height && z < Width;
+Bool Chunk::is_valid_position(Position::BlockLocal pos) {
+    return pos.x() < Width && pos.y() < Height && pos.z() < Width;
 }
 
 U64 Chunk::pos(U32 x, U32 y, U32 z) {
     return x + Width * y + Width * Height * z;
 }
 
+AABB Chunk::block_bounds(Position::BlockLocal pos) {
+    return {
+        {pos.x(), pos.y(), pos.z()},
+        {pos.x() + 1, pos.y() + 1, pos.z() + 1},
+    };
+}
+
 }
diff --git a/src/World/Chunk.hpp b/src/World/Chunk.hpp
index 0b00c97..ed3220d 100644
--- a/src/World/Chunk.hpp
+++ b/src/World/Chunk.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "../Common/Sizes.hpp"
+#include "../Math/AABB.hpp"
 #include "ChunkDimensions.hpp"
 #include "BiomeType.hpp"
 #include "BlockType.hpp"
@@ -35,8 +36,6 @@ public:
     const BlockData& at(Position::BlockLocal pos) const;
     BlockData& at(Position::BlockLocal pos);
 
-    Bool is_empty(U32 x, U32 y, U32 z) const;
-
     struct Details {
         Matrix<Width, Width> landmass_values{};
         Matrix<Width, Width> hill_values{};
@@ -55,7 +54,8 @@ public:
     Bool is_damaged() const;
     void damage();
 
-    static Bool is_valid_position(U32 x, U32 y, U32 z);
+    static Bool is_valid_position(Position::BlockLocal pos);
+    static AABB block_bounds(Position::BlockLocal pos);
 private:
     static U64 pos(U32 x, U32 y, U32 z);
 
diff --git a/src/World/Generation/Decoration.cpp b/src/World/Generation/Decoration.cpp
index 556b5e7..0623c05 100644
--- a/src/World/Generation/Decoration.cpp
+++ b/src/World/Generation/Decoration.cpp
@@ -4,11 +4,11 @@
 
 namespace MC::World::Generation {
 void Decorator::put_block(Chunk& chunk, Pos pos, BlockType block) {
-    if (!Chunk::is_valid_position(pos.x(), pos.y(), pos.z())) {
+    if (!Chunk::is_valid_position(pos)) {
         return;
     }
 
-    auto& place = chunk.at(pos.x(), pos.y(), pos.z());
+    auto& place = chunk.at(pos);
     if (place.empty()) {
         place = {block};
     }
@@ -88,7 +88,7 @@ void TreeDecorator::draw_tree(Chunk& chunk, Pos pos) const {
     }
 }
 
-Bool TreeDecorator::is_valid_position(Vector<3, UInt> pos) {
+Bool TreeDecorator::is_valid_position(Pos pos) {
     Int tree_radius = s_tree_radius;
     return (Int)pos.x() - tree_radius >= 0
         && pos.x() + tree_radius <= Chunk::Width
diff --git a/src/World/Generation/Decoration.hpp b/src/World/Generation/Decoration.hpp
index 2f119ff..c157688 100644
--- a/src/World/Generation/Decoration.hpp
+++ b/src/World/Generation/Decoration.hpp
@@ -7,7 +7,7 @@ namespace MC::World::Generation {
 
 class Decorator {
 public:
-    using Pos = Vector<3, UInt>;
+    using Pos = Position::BlockLocal;
 
     virtual ~Decorator() = default;