summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2023-12-07 02:14:47 +0100
committerMel <einebeere@gmail.com>2023-12-07 02:14:47 +0100
commitefd17623627607a26f33dac8f7ef1a1ddc931907 (patch)
tree76cf0389ae927bfc697c830155d926843178030e /src
parent581f50e0bd45a19282d7958975997d376512b195 (diff)
downloadmeowcraft-efd17623627607a26f33dac8f7ef1a1ddc931907.tar.zst
meowcraft-efd17623627607a26f33dac8f7ef1a1ddc931907.zip
Gather all possibly colliding blocks in the player move domain for collision detection
Diffstat (limited to 'src')
-rw-r--r--src/Entities/Player.cpp43
-rw-r--r--src/Entities/Player.hpp2
-rw-r--r--src/Math/AABB.hpp8
-rw-r--r--src/World/Chunk.hpp12
-rw-r--r--src/World/ChunkIndex.hpp4
5 files changed, 52 insertions, 17 deletions
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 5d41ad0..fb88222 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -12,17 +12,15 @@ void Player::update(const Time& time, GFX::Window& window, GFX::Camera& camera,
     Real z = key(GLFW_KEY_S) - key(GLFW_KEY_W);
     Real boost = key(GLFW_KEY_LEFT_CONTROL) * 75.0f;
 
-    auto move_speed = (20.0f + boost) * time.delta();
+    auto move_speed = (10.0f + boost) * time.delta();
     auto rotation_speed = 0.1f;
 
     auto direction = m_transform.right() * x + Vec3(0, y, 0) + m_transform.forward() * z;
     auto destination = m_transform.position() + direction * move_speed;
 
-    auto collisions = colliding_terrain(destination, world);
-    for (auto collision : collisions) {
-        auto original = destination;
+    auto collision_domain = terrain_collision_domain(m_transform.position(), destination, world);
+    for (auto collision : collision_domain) {
         destination = collision_reposition(m_transform.position(), destination, collision);
-        if (!original.mostly_equal(destination)) break;
     }
 
     move_to(destination);
@@ -60,21 +58,34 @@ void Player::update_camera_position(GFX::Camera& camera) {
     camera.set_angles(m_transform.rotation());
 }
 
-FlexArray<AABB, Player::MaxCollidingTerrain> Player::colliding_terrain(
-    Position::World new_position,
+std::vector<AABB> Player::terrain_collision_domain(
+    Position::World from, Position::World to,
     World::World& world
 ) {
-    FlexArray<AABB, MaxCollidingTerrain> colliding_blocks;
+    auto domain_box = bounding_box_for_position(from).unite(bounding_box_for_position(to));
+    std::vector<AABB> colliding_blocks;
+
+    // TODO: Unbind from chunks and loop through all the
+    // blocks individually inside domain.
+    // This will be more efficient and actually accurate,
+    // since right now if you're fast enough you can clip
+    // through whole chunks.
+    auto add_colliding = [&](Position::World chunk_pos, Position::BlockLocal pos, World::Chunk::BlockData& b) {
+        if (b.type == World::BlockType::Air) return;
+        auto block_bounds = World::Chunk::block_bounds(pos).offset(chunk_pos);
+        if (domain_box.collides(block_bounds)) colliding_blocks.push_back(block_bounds);
+    };
 
-    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 chunk_from = world.chunks().find(to);
+    if (chunk_from.chunk.has_value()) {
+        auto position = chunk_from.chunk.value().position();
+        chunk_from.chunk->for_each([&](auto p, auto b) { add_colliding(position, p, b); });
+    }
 
-        auto block = world.block_at(block_position);
-        if (!block.empty()) {
-            colliding_blocks.push_back(World::Chunk::block_bounds(block_position.to_local()));
-        }
+    auto chunk_to = world.chunks().find(to);
+    if (chunk_to.chunk.has_value()) {
+        auto position = chunk_to.chunk.value().position();
+        chunk_to.chunk->for_each([&](auto p, auto b) { add_colliding(position, p, b); });
     }
 
     return colliding_blocks;
diff --git a/src/Entities/Player.hpp b/src/Entities/Player.hpp
index 7238e80..3ae10ff 100644
--- a/src/Entities/Player.hpp
+++ b/src/Entities/Player.hpp
@@ -29,7 +29,7 @@ private:
     void update_camera_position(GFX::Camera& camera);
 
     static constexpr UInt MaxCollidingTerrain = 34;
-    static FlexArray<AABB, MaxCollidingTerrain> colliding_terrain(Position::World new_position, World::World& world);
+    static std::vector<AABB> terrain_collision_domain(Position::World from, Position::World to, 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/Math/AABB.hpp b/src/Math/AABB.hpp
index 22de760..53ce6d2 100644
--- a/src/Math/AABB.hpp
+++ b/src/Math/AABB.hpp
@@ -2,6 +2,7 @@
 
 #include <array>
 #include "Vector.hpp"
+#include "../Common/Lambda.hpp"
 
 struct AABB {
     AABB() = default;
@@ -60,6 +61,13 @@ struct AABB {
         return {center() - new_size / 2, center() + new_size / 2};
     }
 
+    AABB unite(AABB with) const {
+        return {
+            min.zip(with.min, LAMBDA(std::min, 2)),
+            max.zip(with.max, LAMBDA(std::max, 2))
+        };
+    }
+
     AABB collision_response(Vector<3> v, AABB against) const;
 
     Vector<3> min, max;
diff --git a/src/World/Chunk.hpp b/src/World/Chunk.hpp
index ed3220d..9a29284 100644
--- a/src/World/Chunk.hpp
+++ b/src/World/Chunk.hpp
@@ -48,6 +48,18 @@ public:
     void set_details(const Details& details) { m_details = details; }
     Details& details(){ return m_details; }
 
+    template <typename F>
+    void for_each(F f) {
+        for (U32 x = 0; x < Width; ++x) {
+            for (U32 y = 0; y < Height; ++y) {
+                for (U32 z = 0; z < Width; ++z) {
+                    Position::BlockLocal pos{x, y, z};
+                    f(pos, at(x, y, z));
+                }
+            }
+        }
+    }
+
     ChunkIndex index() const;
     Vector<3> position() const;
 
diff --git a/src/World/ChunkIndex.hpp b/src/World/ChunkIndex.hpp
index 2e4fa67..bc61f3d 100644
--- a/src/World/ChunkIndex.hpp
+++ b/src/World/ChunkIndex.hpp
@@ -21,6 +21,10 @@ struct ChunkIndex {
         return {x * Width + local.x(), local.y(), y * Width + local.z()};
     }
 
+    Position::BlockWorld world_position() const {
+        return local_to_world_position({0, 0, 0});
+    }
+
     static ChunkIndex from_position(Position::BlockWorld pos) {
         I32 chunk_x = std::floor((Real)pos.x() / ChunkDimensions::Width);
         I32 chunk_y = std::floor((Real)pos.z() / ChunkDimensions::Width);