diff options
| author | Mel <einebeere@gmail.com> | 2023-12-07 02:14:47 +0100 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2023-12-07 02:14:47 +0100 |
| commit | efd17623627607a26f33dac8f7ef1a1ddc931907 (patch) | |
| tree | 76cf0389ae927bfc697c830155d926843178030e /src | |
| parent | 581f50e0bd45a19282d7958975997d376512b195 (diff) | |
| download | meowcraft-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.cpp | 43 | ||||
| -rw-r--r-- | src/Entities/Player.hpp | 2 | ||||
| -rw-r--r-- | src/Math/AABB.hpp | 8 | ||||
| -rw-r--r-- | src/World/Chunk.hpp | 12 | ||||
| -rw-r--r-- | src/World/ChunkIndex.hpp | 4 |
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); |
