diff options
| author | Mel <einebeere@gmail.com> | 2023-08-06 04:27:07 +0200 |
|---|---|---|
| committer | Mel <einebeere@gmail.com> | 2023-08-06 04:27:07 +0200 |
| commit | 5a1b126f1f6d55226c2b5068d0c17c428fd29ba8 (patch) | |
| tree | 3acc0240cd8dedd0764eeae6df04e134b04584c8 /src | |
| parent | e6f5f9e03f673db796f1babb308609ca2576db2f (diff) | |
| download | meowcraft-5a1b126f1f6d55226c2b5068d0c17c428fd29ba8.tar.zst meowcraft-5a1b126f1f6d55226c2b5068d0c17c428fd29ba8.zip | |
Create separate Player entity and add bad collision system
Diffstat (limited to 'src')
| -rw-r--r-- | src/Entities/Player.cpp | 80 | ||||
| -rw-r--r-- | src/Entities/Player.hpp | 40 | ||||
| -rw-r--r-- | src/GFX/Util/Primitives.cpp | 6 | ||||
| -rw-r--r-- | src/GFX/Util/Primitives.hpp | 4 | ||||
| -rw-r--r-- | src/Math/AABB.hpp | 25 | ||||
| -rw-r--r-- | src/Math/Matrix.hpp | 3 | ||||
| -rw-r--r-- | src/Math/Rotation.hpp | 25 | ||||
| -rw-r--r-- | src/Math/Vector.hpp | 4 | ||||
| -rw-r--r-- | src/Transform.cpp | 24 | ||||
| -rw-r--r-- | src/Transform.hpp | 40 | ||||
| -rw-r--r-- | src/World/ChunkIndex.hpp | 4 | ||||
| -rw-r--r-- | src/World/Clouds.cpp | 2 | ||||
| -rw-r--r-- | src/World/Position.hpp | 4 | ||||
| -rw-r--r-- | src/World/World.cpp | 6 | ||||
| -rw-r--r-- | src/World/World.hpp | 2 | ||||
| -rw-r--r-- | src/main.cpp | 33 |
16 files changed, 252 insertions, 50 deletions
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) { |
