summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2024-02-02 03:03:36 +0100
committerMel <einebeere@gmail.com>2024-02-02 03:03:36 +0100
commit250e37c742f3ad46f093f4534098cdf8f68a29a9 (patch)
tree29bb86a24e5a987959a455cae13818cf0def8646
parent7b061aee2b4c15d242bb9f18101d6b9ea776c5cd (diff)
downloadmeowcraft-250e37c742f3ad46f093f4534098cdf8f68a29a9.tar.zst
meowcraft-250e37c742f3ad46f093f4534098cdf8f68a29a9.zip
Breaking blocks
-rw-r--r--CMakeLists.txt1
-rw-r--r--src/Entities/Player.cpp31
-rw-r--r--src/Entities/Player.hpp3
-rw-r--r--src/World/ChunkRegistry.hpp4
-rw-r--r--src/World/VoxelTraversal.hpp60
-rw-r--r--src/World/World.cpp11
-rw-r--r--src/World/World.hpp12
7 files changed, 115 insertions, 7 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e98c87c..2c14505 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,6 +63,7 @@ add_executable(meowcraft
src/Common/Lambda.hpp
src/Math/Functions.hpp
src/Common/Casts.hpp
+ src/World/VoxelTraversal.hpp
)
target_link_libraries(meowcraft glfw GLEW::GLEW)
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 66f08c6..a8abb1d 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -23,6 +23,18 @@ void Player::update(const Time& time, GFX::Window& window, GFX::Camera& camera,
rotate(rotational_input(window));
update_camera_position(camera);
+
+ if (window.mouse(GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS)) {
+ auto look_transform = camera_transform();
+ auto look_direction = -look_transform.forward(); // Why does this need to be inverted?
+ auto block = world.traverse(
+ Ray{look_transform.position(), look_direction},
+ 4.0,
+ [](auto b) { return b.type.is_solid(); }
+ );
+
+ if (block != Position::BlockWorld{}) world.break_block(block);
+ }
}
void Player::move(Position::WorldOffset by) {
@@ -203,12 +215,21 @@ std::vector<AABB> Player::terrain_collision_domain(
return colliding_blocks;
}
-void Player::update_camera_position(GFX::Camera& camera) {
- auto camera_position = m_transform.position();
- camera_position.y() += 1.5;
+Transform Player::camera_transform() const {
+ auto position = m_transform.position();
+ position.y() += 1.5;
+ return {
+ position,
+ m_transform.rotation(),
+ m_transform.scale(),
+ };
+}
+
+void Player::update_camera_position(GFX::Camera& camera) const {
+ auto cam_transform = camera_transform();
- camera.set_position(camera_position);
- camera.set_angles(m_transform.rotation());
+ camera.set_position(cam_transform.position());
+ camera.set_angles(cam_transform.rotation());
}
Vec3 Player::directional_input(GFX::Window& window) {
diff --git a/src/Entities/Player.hpp b/src/Entities/Player.hpp
index 5d70559..b1ec8e7 100644
--- a/src/Entities/Player.hpp
+++ b/src/Entities/Player.hpp
@@ -40,7 +40,8 @@ private:
Vec3 walking_velocity(GFX::Window& window, const Time& time, Vec3 input_direction);
Vec3 flying_velocity(GFX::Window& window, const Time& time, Vec3 input_direction);
- void update_camera_position(GFX::Camera& camera);
+ Transform camera_transform() const;
+ void update_camera_position(GFX::Camera& camera) const;
static Vec3 directional_input(GFX::Window& window);
static Rotation rotational_input(GFX::Window& window);
diff --git a/src/World/ChunkRegistry.hpp b/src/World/ChunkRegistry.hpp
index ea887e4..2b87a3a 100644
--- a/src/World/ChunkRegistry.hpp
+++ b/src/World/ChunkRegistry.hpp
@@ -34,7 +34,9 @@ public:
}
void damage() {
- if (status == Status::Done) chunk.value().damage();
+ // if (status == Status::Done) chunk.value().damage();
+ // TODO: Properly damage the chunk, notifying the nearby chunks, too.
+ status = Status::NeedsReification;
}
};
diff --git a/src/World/VoxelTraversal.hpp b/src/World/VoxelTraversal.hpp
new file mode 100644
index 0000000..1638901
--- /dev/null
+++ b/src/World/VoxelTraversal.hpp
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "../Common/Casts.hpp"
+#include "../Math/Ray.hpp"
+#include "Position.hpp"
+
+namespace MC::World::VoxelTraversal {
+
+// Amanatides, John, and Andrew Woo. 1987.
+// "A Fast Voxel Traversal Algorithm for Ray Tracing."
+// https://doi.org/10.2312/EGTP.19871000.
+template <typename P>
+Position::BlockWorld traverse(Ray ray, Real max_distance, P&& predicate) {
+ // Find the voxel grid cell containing the origin of the ray.
+ Position::BlockWorld block_pos = Position::World(ray.origin).round_to_block();
+ Position::BlockWorldOffset const step = {
+ Math::sign(ray.direction.x()),
+ Math::sign(ray.direction.y()),
+ Math::sign(ray.direction.z()),
+ };
+
+ Position::WorldOffset t_max = {
+ (TO(Real, block_pos.x()) + TO(Real, step.x() > 0) - ray.origin.x()) / ray.direction.x(),
+ (TO(Real, block_pos.y()) + TO(Real, step.y() > 0) - ray.origin.y()) / ray.direction.y(),
+ (TO(Real, block_pos.z()) + TO(Real, step.z() > 0) - ray.origin.z()) / ray.direction.z()
+ };
+
+ Position::WorldOffset const t_delta = {
+ TO(Real, step.x()) / ray.direction.x(),
+ TO(Real, step.y()) / ray.direction.y(),
+ TO(Real, step.z()) / ray.direction.z()
+ };
+
+ while (!predicate(block_pos)) {
+ // TODO: Calculate distance exactly.
+ if (ray.origin.distance(Vec3(block_pos)) > max_distance) return {};
+
+ if (t_max.x() < t_max.y()) {
+ if (t_max.x() < t_max.z()) {
+ block_pos.x() += step.x();
+ t_max.x() += t_delta.x();
+ } else {
+ block_pos.z() += step.z();
+ t_max.z() += t_delta.z();
+ }
+ } else {
+ if (t_max.y() < t_max.z()) {
+ block_pos.y() += step.y();
+ t_max.y() += t_delta.y();
+ } else {
+ block_pos.z() += step.z();
+ t_max.z() += t_delta.z();
+ }
+ }
+ }
+
+ return block_pos;
+}
+
+}
diff --git a/src/World/World.cpp b/src/World/World.cpp
index ce15ae8..cc5d91f 100644
--- a/src/World/World.cpp
+++ b/src/World/World.cpp
@@ -47,6 +47,17 @@ Chunk::BlockData World::block_at(Position::BlockWorld pos) {
return {};
}
+void World::break_block(Position::BlockWorld pos) {
+ auto& chunk_data = m_registry.find(pos);
+ if (!chunk_data.chunk.has_value()) return;
+
+ auto& block_data = chunk_data.chunk->at(pos.to_local());
+ if (!block_data.type.is_solid()) return;
+
+ block_data.type = {};
+ chunk_data.damage();
+}
+
std::vector<ChunkIndex> World::get_visible_chunk_indices(const Position::World position) const {
ChunkIndex center = ChunkIndex::from_position(position.round_to_block());
diff --git a/src/World/World.hpp b/src/World/World.hpp
index 3dbd720..af49378 100644
--- a/src/World/World.hpp
+++ b/src/World/World.hpp
@@ -4,8 +4,10 @@
#include "ChunkIndex.hpp"
#include "ChunkRegistry.hpp"
#include "../Compute/Queue.hpp"
+#include "../Math/Ray.hpp"
#include "Generation/ChunkMeshing.hpp"
#include "Generation/Lighting.hpp"
+#include "VoxelTraversal.hpp"
namespace MC::World {
@@ -14,6 +16,16 @@ public:
std::vector<ChunkRegistry::Data*> get_visible_chunks(Position::World position);
Chunk::BlockData block_at(Position::BlockWorld pos);
+ void break_block(Position::BlockWorld pos);
+
+ template <typename F>
+ Position::BlockWorld traverse(Ray ray, Real max_distance, F&& predicate) {
+ return VoxelTraversal::traverse(
+ ray,
+ max_distance,
+ [this, &predicate](Position::BlockWorld pos) { return predicate(block_at(pos)); }
+ );
+ }
Real get_average_chunk_time() const;