summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2023-08-14 03:40:10 +0200
committerMel <einebeere@gmail.com>2023-08-14 03:40:10 +0200
commit7562a79fa214245544cb379423314c3a0766a7f2 (patch)
tree0aaafd06c6026fabc82dbc3454487d009c9043e7
parent5a1b126f1f6d55226c2b5068d0c17c428fd29ba8 (diff)
downloadmeowcraft-7562a79fa214245544cb379423314c3a0766a7f2.tar.zst
meowcraft-7562a79fa214245544cb379423314c3a0766a7f2.zip
Generate AABBs for terrain that collides with Player
-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;