summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2023-08-06 04:27:07 +0200
committerMel <einebeere@gmail.com>2023-08-06 04:27:07 +0200
commit5a1b126f1f6d55226c2b5068d0c17c428fd29ba8 (patch)
tree3acc0240cd8dedd0764eeae6df04e134b04584c8
parente6f5f9e03f673db796f1babb308609ca2576db2f (diff)
downloadmeowcraft-5a1b126f1f6d55226c2b5068d0c17c428fd29ba8.tar.zst
meowcraft-5a1b126f1f6d55226c2b5068d0c17c428fd29ba8.zip
Create separate Player entity and add bad collision system
-rw-r--r--CMakeLists.txt4
-rw-r--r--src/Entities/Player.cpp80
-rw-r--r--src/Entities/Player.hpp40
-rw-r--r--src/GFX/Util/Primitives.cpp6
-rw-r--r--src/GFX/Util/Primitives.hpp4
-rw-r--r--src/Math/AABB.hpp25
-rw-r--r--src/Math/Matrix.hpp3
-rw-r--r--src/Math/Rotation.hpp25
-rw-r--r--src/Math/Vector.hpp4
-rw-r--r--src/Transform.cpp24
-rw-r--r--src/Transform.hpp40
-rw-r--r--src/World/ChunkIndex.hpp4
-rw-r--r--src/World/Clouds.cpp2
-rw-r--r--src/World/Position.hpp4
-rw-r--r--src/World/World.cpp6
-rw-r--r--src/World/World.hpp2
-rw-r--r--src/main.cpp33
17 files changed, 256 insertions, 50 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c828d5e..fc29dd3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -59,6 +59,10 @@ 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
)
target_link_libraries(meowcraft glfw GLEW::GLEW)
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
new file mode 100644
index 0000000..175b59e
--- /dev/null
+++ b/src/Entities/Player.cpp
@@ -0,0 +1,80 @@
+#include "Player.hpp"
+
+namespace MC::Entities {
+
+void Player::update(const Time& time, GFX::Window& window, GFX::Camera& camera, World::World& world) {
+ auto r = window.mouse_delta();
+
+ auto key = [&](Int k) -> Real { return window.key(k, GLFW_PRESS); };
+
+ Real x = key(GLFW_KEY_D) - key(GLFW_KEY_A);
+ Real y = key(GLFW_KEY_SPACE) - key(GLFW_KEY_LEFT_SHIFT);
+ 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 rotation_speed = 0.1f;
+
+ 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);
+ rotate({r.y() * rotation_speed, r.x() * rotation_speed, 0.0f});
+
+ update_camera_position(camera);
+}
+
+void Player::move(Position::WorldOffset by) {
+ m_transform.position() += by;
+}
+
+void Player::rotate(Rotation by) {
+ m_transform.rotation() += by;
+ m_transform.rotation().pitch() = std::clamp(m_transform.rotation().pitch(), -89.0, 89.0);
+}
+
+void Player::move_to(Position::World to) {
+ m_transform.position() = to;
+}
+
+void Player::rotate_to(Rotation to) {
+ m_transform.rotation() = to;
+}
+
+AABB Player::bounds() const {
+ return bounding_box_for_position(m_transform.position());
+}
+
+void Player::update_camera_position(GFX::Camera& camera) {
+ auto camera_position = m_transform.position();
+ camera_position.y() += 1.5;
+
+ camera.set_position(camera_position);
+ 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();
+
+ 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;
+ }
+
+ return false;
+}
+
+AABB Player::bounding_box_for_position(Position::World position) {
+ Vec3 box_start = {
+ position.x() - s_bounds.max.x() / 2,
+ position.y(),
+ position.z() - s_bounds.max.z() / 2,
+ };
+
+ return s_bounds.offset(box_start);
+}
+
+}
diff --git a/src/Entities/Player.hpp b/src/Entities/Player.hpp
new file mode 100644
index 0000000..86d8c90
--- /dev/null
+++ b/src/Entities/Player.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "../Time.hpp"
+#include "../Transform.hpp"
+#include "../GFX/Camera.hpp"
+#include "../World/World.hpp"
+#include "../GFX/Window.hpp"
+#include "../Math/AABB.hpp"
+#include "../Math/Rotation.hpp"
+#include "../World/Position.hpp"
+
+namespace MC::Entities {
+
+class Player {
+public:
+ explicit Player(Position::World position) : m_transform(position) {}
+
+ void update(const Time& time, GFX::Window& window, GFX::Camera& camera, World::World& world);
+
+ void move(Position::WorldOffset by);
+ void move_to(Position::World to);
+
+ void rotate(Rotation by);
+ void rotate_to(Rotation to);
+
+ AABB bounds() const;
+private:
+ void update_camera_position(GFX::Camera& camera);
+
+ static Bool collides_with_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);
+
+ Transform m_transform;
+
+ static inline AABB s_bounds{{0.35, 1.8, 0.35}};
+};
+
+}
diff --git a/src/GFX/Util/Primitives.cpp b/src/GFX/Util/Primitives.cpp
index d2c3690..4b44864 100644
--- a/src/GFX/Util/Primitives.cpp
+++ b/src/GFX/Util/Primitives.cpp
@@ -2,7 +2,7 @@
namespace MC::GFX::Util::Primitives {
-PlanePrimitive plane(Math::AABB aabb, FaceSet face) {
+PlanePrimitive plane(AABB aabb, FaceSet face) {
decltype(PlanePrimitive::positions) positions;
auto [min, max] = aabb;
@@ -55,7 +55,7 @@ PlanePrimitive plane(Math::AABB aabb, FaceSet face) {
return {positions, {normal, normal, normal, normal}, {0, 1, 2, 2, 3, 0}};
}
-BoxPrimitive box(Math::AABB aabb, FaceSet faces) {
+BoxPrimitive box(AABB aabb, FaceSet faces) {
BoxPrimitive box{};
auto [min, max] = aabb;
@@ -65,7 +65,7 @@ BoxPrimitive box(Math::AABB aabb, FaceSet faces) {
FaceSet face = (FaceSet::Value)face_value;
if ((faces & face) == 0) continue;
- Math::AABB face_aabb;
+ AABB face_aabb;
switch (face) {
case FaceSet::Front:
face_aabb = {min, {max.x(), max.y(), min.z()}};
diff --git a/src/GFX/Util/Primitives.hpp b/src/GFX/Util/Primitives.hpp
index b96bc00..a267130 100644
--- a/src/GFX/Util/Primitives.hpp
+++ b/src/GFX/Util/Primitives.hpp
@@ -39,9 +39,9 @@ struct Primitive {
};
using PlanePrimitive = Primitive<4>;
-PlanePrimitive plane(Math::AABB aabb, FaceSet face);
+PlanePrimitive plane(AABB aabb, FaceSet face);
using BoxPrimitive = Primitive<4 * 6>;
-BoxPrimitive box(Math::AABB aabb, FaceSet faces = FaceSet::all());
+BoxPrimitive box(AABB aabb, FaceSet faces = FaceSet::all());
}
diff --git a/src/Math/AABB.hpp b/src/Math/AABB.hpp
index 2c02abf..11d26a8 100644
--- a/src/Math/AABB.hpp
+++ b/src/Math/AABB.hpp
@@ -1,10 +1,27 @@
#pragma once
-#include "Vector.hpp"
-namespace Math {
+#include <array>
+#include "Vector.hpp"
struct AABB {
+ AABB() = default;
+ AABB(Vector<3> min, Vector<3> max) : min(min), max(max) {}
+ explicit AABB(Vector<3> max) : max(max) {}
+
+ std::array<Vector<3>, 8> corners() const {
+ return {{
+ {min.x(), min.y(), min.z()},
+ {min.x(), min.y(), max.z()},
+ {min.x(), max.y(), min.z()},
+ {min.x(), max.y(), max.z()},
+ {max.x(), min.y(), min.z()},
+ {max.x(), min.y(), max.z()},
+ {max.x(), max.y(), min.z()},
+ {max.x(), max.y(), max.z()},
+ }};
+ }
+
+ AABB offset(Vector<3> by) const { return {min + by, max + by}; }
+
Vector<3> min, max;
};
-
-}
diff --git a/src/Math/Matrix.hpp b/src/Math/Matrix.hpp
index 41d3661..c4532c3 100644
--- a/src/Math/Matrix.hpp
+++ b/src/Math/Matrix.hpp
@@ -3,7 +3,6 @@
#include <sstream>
#include "../Common/Sizes.hpp"
#include "Rotation.hpp"
-#include "Trig.hpp"
template <uint R, uint C, typename T = Real>
struct Matrix {
@@ -47,7 +46,7 @@ struct Matrix {
}
static Matrix<4, 4, T> rotation(Rotation angles) {
- auto radians = angles.vector.map([](auto a) { return Math::radians(a); });
+ auto radians = angles.radians();
auto c = radians.map([](auto a) { return cos(a); });
auto s = radians.map([](auto a) { return sin(a); });
diff --git a/src/Math/Rotation.hpp b/src/Math/Rotation.hpp
index 83c1109..d5bc023 100644
--- a/src/Math/Rotation.hpp
+++ b/src/Math/Rotation.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <cmath>
+#include "Trig.hpp"
#include "Vector.hpp"
struct Rotation {
@@ -14,10 +15,19 @@ struct Rotation {
vector = wrap({pitch, yaw, roll });
}
+ Vector<3> radians() const {
+ return vector.map([](auto a) { return Math::radians(a); });
+ }
+
Rotation operator+(Rotation other) const {
return wrap(vector + other.vector);
}
+ Rotation& operator+=(const Rotation& other) {
+ *this = *this + other;
+ return *this;
+ }
+
std::string string() const {
return vector.string();
}
@@ -26,17 +36,14 @@ struct Rotation {
return v.map([](auto a) { return fmod(a, 360.0f); });
}
- Real& pitch() {
- return vector[0];
- }
+ Real& pitch() { return vector.x(); }
+ const Real& pitch() const { return vector.x(); }
- Real& yaw() {
- return vector[1];
- }
+ Real& yaw() { return vector.y(); }
+ const Real& yaw() const { return vector.y(); }
- Real& roll() {
- return vector[2];
- }
+ Real& roll() { return vector.z(); }
+ const Real& roll() const { return vector.z(); }
Vector<3> vector;
}; \ No newline at end of file
diff --git a/src/Math/Vector.hpp b/src/Math/Vector.hpp
index 3d9cb0e..a7c3782 100644
--- a/src/Math/Vector.hpp
+++ b/src/Math/Vector.hpp
@@ -190,3 +190,7 @@ struct Vector {
T elements[S];
};
+
+using Vec2 = Vector<2, Real>;
+using Vec3 = Vector<3, Real>;
+using Vec4 = Vector<4, Real>; \ No newline at end of file
diff --git a/src/Transform.cpp b/src/Transform.cpp
new file mode 100644
index 0000000..72be8ea
--- /dev/null
+++ b/src/Transform.cpp
@@ -0,0 +1,24 @@
+#include "Transform.hpp"
+#include "Math/Common.hpp"
+
+namespace MC {
+
+Vector<3> Transform::forward() const {
+ return unit_vector({0, 0, 1});
+}
+
+Vector<3> Transform::right() const {
+ return unit_vector({1, 0, 0});
+}
+
+Vector<3> Transform::up() const {
+ return unit_vector({0, 1, 0});
+}
+
+Vector<3> Transform::unit_vector(Vector<3> axis) const {
+ auto rotation = Matrix<4, 4>::rotation(m_rotation);
+ auto result = rotation.transpose() * Vector<4>{axis.x(), axis.y(), axis.z(), 1.0f};
+ return {result.x(), result.y(), result.z()};
+}
+
+}
diff --git a/src/Transform.hpp b/src/Transform.hpp
new file mode 100644
index 0000000..ea7f9b3
--- /dev/null
+++ b/src/Transform.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "Math/Rotation.hpp"
+#include "World/Position.hpp"
+
+namespace MC {
+
+class Transform {
+public:
+ Transform() : m_scale(1) {}
+ explicit Transform(Position::World position) : m_position(position), m_scale(1) {}
+ Transform(Position::World position, Rotation rotation, Vector<3> scale)
+ : m_position(position),
+ m_rotation(rotation),
+ m_scale(scale) {}
+
+ Vector<3> forward() const;
+ Vector<3> right() const;
+ Vector<3> up() const;
+
+ Position::World& position() { return m_position; }
+ const Position::World& position() const { return m_position; }
+
+ Rotation& rotation() { return m_rotation; }
+ const Rotation& rotation() const { return m_rotation; }
+
+ Vector<3>& scale() { return m_scale; }
+ const Vector<3>& scale() const { return m_scale; }
+private:
+ Vector<3> unit_vector(Vector<3> axis) const;
+
+ // TODO: Use a non-MC::World position class.
+ // I don't want coupling between the game implementation
+ // and what is essentially engine code.
+ Position::World m_position;
+ Rotation m_rotation;
+ Vector<3> m_scale;
+};
+
+}
diff --git a/src/World/ChunkIndex.hpp b/src/World/ChunkIndex.hpp
index 70de99f..2e4fa67 100644
--- a/src/World/ChunkIndex.hpp
+++ b/src/World/ChunkIndex.hpp
@@ -22,8 +22,8 @@ struct ChunkIndex {
}
static ChunkIndex from_position(Position::BlockWorld pos) {
- I32 chunk_x = std::round(pos.x() / ChunkDimensions::Width);
- I32 chunk_y = std::round(pos.z() / ChunkDimensions::Width);
+ I32 chunk_x = std::floor((Real)pos.x() / ChunkDimensions::Width);
+ I32 chunk_y = std::floor((Real)pos.z() / ChunkDimensions::Width);
return {chunk_x, chunk_y};
}
diff --git a/src/World/Clouds.cpp b/src/World/Clouds.cpp
index 2567985..b30c0ce 100644
--- a/src/World/Clouds.cpp
+++ b/src/World/Clouds.cpp
@@ -103,7 +103,7 @@ GFX::Mesh Clouds::create_mesh(const CloudMatrix& cloud_matrix) {
if (!neighbors[2]) faces |= FaceSet::Front;
if (!neighbors[3]) faces |= FaceSet::Back;
- auto aabb = Math::AABB{{x, 0, y}, {x + 1, 1, y + 1}};
+ auto aabb = AABB{{x, 0, y}, {x + 1, 1, y + 1}};
auto box = GFX::Util::Primitives::box(aabb, (FaceSet::Value)faces);
builder.primitive(box);
}
diff --git a/src/World/Position.hpp b/src/World/Position.hpp
index bc874c0..91ec306 100644
--- a/src/World/Position.hpp
+++ b/src/World/Position.hpp
@@ -53,7 +53,7 @@ public:
BlockLocal to_local() const {
using namespace MC::World::ChunkDimensions;
- return {Math::mod(x(), Width), y(), Math::mod(z(), Width)};
+ return {Math::mod(x(), Width), std::clamp<I64>(y(), 0, Height), Math::mod(z(), Width)};
}
};
@@ -73,7 +73,7 @@ public:
MC_POSITION_MAKE_DEFAULT_CONSTRUCTORS(World, Real)
BlockWorld round_to_block() const {
- auto rounded = map([](auto x) { return std::round(x); });
+ auto rounded = map([](auto x) { return std::floor(x); });
return {rounded.x(), rounded.y(), rounded.z()};
}
};
diff --git a/src/World/World.cpp b/src/World/World.cpp
index 089c498..ce15ae8 100644
--- a/src/World/World.cpp
+++ b/src/World/World.cpp
@@ -41,6 +41,12 @@ std::vector<ChunkRegistry::Data*> World::get_visible_chunks(Position::World posi
return chunks;
}
+Chunk::BlockData World::block_at(Position::BlockWorld pos) {
+ auto& data = m_registry.find(pos);
+ if (data.chunk.has_value()) return data.chunk->at(pos.to_local());
+ return {};
+}
+
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 e3b08f5..3bf05f8 100644
--- a/src/World/World.hpp
+++ b/src/World/World.hpp
@@ -13,6 +13,8 @@ class World {
public:
std::vector<ChunkRegistry::Data*> get_visible_chunks(Position::World position);
+ Chunk::BlockData block_at(Position::BlockWorld pos);
+
Real get_average_chunk_time() const;
private:
std::vector<ChunkIndex> get_visible_chunk_indices(Position::World position) const;
diff --git a/src/main.cpp b/src/main.cpp
index 815de28..9dd42c9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -12,6 +12,7 @@
#include "GFX/Image/PPMParser.hpp"
#include "World/Clouds.hpp"
#include "World/World.hpp"
+#include "Entities/Player.hpp"
#define APP_NAME "Meowcraft"
@@ -23,7 +24,6 @@
void run();
void render(MC::GFX::Mesh&, MC::GFX::Texture&);
-void process_input(MC::GFX::Window&, MC::GFX::Camera&, MC::Time&);
void setup_gl();
void fix_macos_render(const MC::GFX::Window&);
@@ -57,7 +57,6 @@ void run() {
MC::World::World world;
MC::GFX::Camera camera{};
- camera.set_position({0, MC::World::Chunk::Height / 2.0, 0});
MC::GFX::Shading::Program program(
MC::GFX::Shading::Shader::create_vertex(),
@@ -83,6 +82,8 @@ void run() {
MC::World::Clouds clouds{ASPECT, FOV, 0.1f, 1000.0f, sky_color, sun_direction};
+ MC::Entities::Player player{{0, MC::World::Chunk::Height / 2.0, 0}};
+
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
@@ -103,7 +104,11 @@ void run() {
fix_macos_render(window);
#endif
- process_input(window, camera, time);
+ if (window.key(GLFW_KEY_ESCAPE, GLFW_PRESS)) {
+ window.close();
+ }
+
+ player.update(time, window, camera, world);
clouds.update(time);
glClearColor(sky_color.x(), sky_color.y(), sky_color.z(), 1.0f); // #DBDBDB
@@ -142,28 +147,6 @@ void render(MC::GFX::Mesh& mesh, MC::GFX::Texture& texture) {
texture.unbind();
}
-void process_input(MC::GFX::Window& window, MC::GFX::Camera& camera, MC::Time& time) {
- if (window.key(GLFW_KEY_ESCAPE, GLFW_PRESS)) {
- window.close();
- }
-
- auto r = window.mouse_delta();
-
- auto key = [&](Int k) -> Real { return window.key(k, GLFW_PRESS); };
-
- Real x = key(GLFW_KEY_D) - key(GLFW_KEY_A);
- Real y = key(GLFW_KEY_SPACE) - key(GLFW_KEY_LEFT_SHIFT);
- 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 rotation_speed = 5.0f * time.delta();
-
- camera.move_relative({x * move_speed, 0.0f, z * move_speed});
- camera.move({0.0f, y * move_speed, 0.0f});
- camera.rotate({r.y() * rotation_speed, r.x() * rotation_speed, 0.0f});
-}
-
void setup_gl() {
GLenum error;
if ((error = glewInit()) != GLEW_OK) {