diff --git a/include/Cubed/gameplay/client_player.hpp b/include/Cubed/gameplay/client_player.hpp index d75fd27..5e755b5 100644 --- a/include/Cubed/gameplay/client_player.hpp +++ b/include/Cubed/gameplay/client_player.hpp @@ -1,5 +1,4 @@ #pragma once -#include "Cubed/AABB.hpp" #include "Cubed/constants.hpp" #include "Cubed/gameplay/block.hpp" #include "Cubed/gameplay/chunk_pos.hpp" @@ -39,7 +38,6 @@ public: const ChunkPosSet& get_chunk_pos_set() const; ChunkPosSet get_chunk_pos_set(); - static AABB get_aabb(const glm::vec3& pos); const glm::vec3& get_front() const; const std::optional& get_look_block_pos() const; @@ -102,13 +100,11 @@ private: bool m_sprinting = false; bool m_underwater = false; - glm::vec3 move_distance{0.0f, 0.0f, 0.0f}; // player is tow block tall, the pos is the lower pos ChunkPos m_last_chunk_pos{0, 0}; glm::vec3 m_front{0, 0, -1}; glm::vec3 m_right{0, 0, 0}; - static constexpr glm::vec3 M_SIZE{0.6f, 1.8f, 0.6f}; MouseState m_mouse_state{}; GameMode m_game_mode = CREATIVE; @@ -129,10 +125,6 @@ private: void update_move(float delta_time); - void update_x_move(glm::vec3& player_pos); - void update_y_move(glm::vec3& player_pos); - void update_z_move(glm::vec3& player_pos); - void update_player_chunk(); void play_walk_sound(float dt); diff --git a/include/Cubed/gameplay/entity.hpp b/include/Cubed/gameplay/entity.hpp index 199d318..e600bf2 100644 --- a/include/Cubed/gameplay/entity.hpp +++ b/include/Cubed/gameplay/entity.hpp @@ -92,6 +92,15 @@ public: MoveState& move_state(); Direction& direction(); + const Velocity& velocity() const; + const Position& pos() const; + const WalkPose& walk_pose() const; + const Orientation& angle() const; + const Movement& movement() const; + const Gravity& gravity() const; + const MoveState& move_state() const; + const Direction& direction() const; + protected: Position m_pos; WalkPose m_walk_pose; diff --git a/include/Cubed/gameplay/player.hpp b/include/Cubed/gameplay/player.hpp index 09deb0b..750786d 100644 --- a/include/Cubed/gameplay/player.hpp +++ b/include/Cubed/gameplay/player.hpp @@ -1,4 +1,6 @@ #pragma once +#include "glm/ext/vector_float3.hpp" + #include #include namespace Cubed { @@ -17,5 +19,5 @@ inline Gait get_gait_from_id(int id) { throw std::runtime_error("Unknown Gait"); } } - +static constexpr glm::vec3 PLAYER_SIZE{0.6f, 1.8f, 0.6f}; } // namespace Cubed diff --git a/include/Cubed/gameplay/systems/physical_system.hpp b/include/Cubed/gameplay/systems/physical_system.hpp new file mode 100644 index 0000000..f606621 --- /dev/null +++ b/include/Cubed/gameplay/systems/physical_system.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "Cubed/gameplay/entity.hpp" +#include "Cubed/gameplay/world.hpp" +namespace Cubed { +class PhysicalSystem { +public: + static glm::vec3 get_move_distance(float dt, const Entity& e); + static std::tuple update(float dt, Entity& e, + World& world); + static std::tuple + update(float dt, Entity& e, World& world, glm::vec3& moved_pos); + +private: +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/gameplay/systems/speed_system.hpp b/include/Cubed/gameplay/systems/speed_system.hpp index 2a736cb..6537db6 100644 --- a/include/Cubed/gameplay/systems/speed_system.hpp +++ b/include/Cubed/gameplay/systems/speed_system.hpp @@ -5,58 +5,7 @@ namespace Cubed { class SpeedSystem { public: - static void update(float dt, Entity& e) { - auto& m_velocity = e.velocity(); - auto& m_move_state = e.move_state(); - auto& m_movement = e.movement(); - auto& direction = e.direction(); - auto& m_gravity = e.gravity(); - // calculate speed - if (m_move_state.forward || m_move_state.back || m_move_state.left || - m_move_state.right) { - direction.value = glm::vec3(0.0f, 0.0f, 0.0f); - m_velocity.value.x += m_movement.acceleration * dt; - m_velocity.value.z += m_movement.acceleration * dt; - if (m_velocity.value.x > m_velocity.max.x) { - m_velocity.value.x = m_velocity.max.x; - } - if (m_velocity.value.z > m_velocity.max.z) { - m_velocity.value.z = m_velocity.max.z; - } - } else { - m_velocity.value.x += -m_movement.deceleration * dt; - m_velocity.value.z += -m_movement.deceleration * dt; - if (m_velocity.value.z < 0.0f) { - m_velocity.value.z = 0.0f; - } - if (m_velocity.value.x < 0.0f) { - m_velocity.value.x = 0.0f; - } - if (m_velocity.value.z < 0.0f && m_velocity.value.x < 0.0f) { - direction.value = glm::vec3(0.0f, 0.0f, 0.0f); - } - } - if (m_move_state.is_fly) { - if (m_move_state.up) { - m_velocity.value.y = m_velocity.max.y; - } - - if (m_move_state.down) { - m_velocity.value.y = -m_velocity.max.y; - } - - if (!m_move_state.down && !m_move_state.up) { - m_velocity.value.y = 0.0f; - } - } else { - if (m_move_state.up && m_move_state.can_up) { - m_velocity.value.y = m_movement.jump_power; - m_move_state.can_up = false; - } - - m_velocity.value.y += -m_gravity.value * dt; - } - } + static void update(float dt, Entity& e); private: }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c3f538d..e64ed11 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -98,4 +98,6 @@ target_sources(${PROJECT_NAME} gameplay/chunk.cpp gameplay/hitbox_manager.cpp gameplay/entity.cpp + gameplay/systems/physical_system.cpp + gameplay/systems/speed_system.cpp ) \ No newline at end of file diff --git a/src/gameplay/client_player.cpp b/src/gameplay/client_player.cpp index 5cd5a2d..b9fb33b 100644 --- a/src/gameplay/client_player.cpp +++ b/src/gameplay/client_player.cpp @@ -4,6 +4,8 @@ #include "Cubed/config.hpp" #include "Cubed/debug_collector.hpp" #include "Cubed/gameplay/client_world.hpp" +#include "Cubed/gameplay/hitbox_manager.hpp" +#include "Cubed/gameplay/systems/physical_system.hpp" #include "Cubed/gameplay/systems/speed_system.hpp" namespace {} // namespace @@ -11,13 +13,6 @@ namespace Cubed { ClientPlayer::ClientPlayer(ClientWorld& world) : m_world(world) {} ClientPlayer::~ClientPlayer() {} -AABB ClientPlayer::get_aabb(const glm::vec3& pos) { - glm::vec3 half = M_SIZE * 0.5f; - - glm::vec3 center{pos.x, pos.y + half.y, pos.z}; - - return AABB{center, half}; -} const glm::vec3& ClientPlayer::get_front() const { return m_front; } const std::optional& ClientPlayer::get_look_block_pos() const { @@ -318,7 +313,8 @@ void ClientPlayer::place_block(float dt) { glm::ivec3 near_pos = m_look_block->pos + m_look_block->normal; if (!m_world.is_solid(near_pos)) { AABB block_box = ClientWorld::get_block_aabb(near_pos); - AABB player_box = get_aabb(get_player_pos()); + AABB player_box = HitboxManager::aabb("cubed:player"); + player_box.center += get_player_pos(); if (!player_box.intersects(block_box)) { m_world.report_block_change(near_pos, type); } @@ -368,11 +364,6 @@ void ClientPlayer::update_move(float delta_time) { update_direction(); - move_distance = {m_direction.value.x * m_velocity.value.x * delta_time, - 0.0f, - m_direction.value.z * m_velocity.value.z * delta_time}; - move_distance.y = m_velocity.value.y * delta_time; - // ensure the thread safe glm::vec3 player_pos; @@ -381,12 +372,15 @@ void ClientPlayer::update_move(float delta_time) { player_pos = m_pos.value; } - // y - update_y_move(player_pos); - // x - update_x_move(player_pos); - - update_z_move(player_pos); + if (m_game_mode == SPECTATOR) { + player_pos += PhysicalSystem::get_move_distance(delta_time, *this); + } else { + auto [x, y, z] = + PhysicalSystem::update(delta_time, *this, m_world, player_pos); + if (!x || !z) { + m_sprinting = false; + } + } if (player_pos.y < -15.0f) { Logger::warn("y is tow low"); @@ -413,109 +407,6 @@ void ClientPlayer::update_move(float delta_time) { } } -void ClientPlayer::update_x_move(glm::vec3& player_pos) { - player_pos.x += move_distance.x; - if (m_game_mode == SPECTATOR) { - return; - } - AABB player_box = get_aabb(player_pos); - glm::vec3 min = player_box.min(); - glm::vec3 max = player_box.max(); - - int minx = std::floor(min.x); - int maxx = std::floor(max.x); - int miny = std::floor(min.y); - int maxy = std::floor(max.y); - int minz = std::floor(min.z); - int maxz = std::floor(max.z); - - for (int x = minx; x <= maxx; ++x) { - for (int y = miny; y <= maxy; ++y) { - for (int z = minz; z <= maxz; ++z) { - glm::ivec3 block_pos{x, y, z}; - if (!m_world.can_pass_block(block_pos)) { - AABB block_box = ClientWorld::get_block_aabb(block_pos); - if (player_box.intersects(block_box)) { - m_sprinting = false; - player_pos.x -= move_distance.x; - return; - } - } - } - } - } -} - -void ClientPlayer::update_y_move(glm::vec3& player_pos) { - player_pos.y += move_distance.y; - if (m_game_mode == SPECTATOR) { - return; - } - AABB player_box = get_aabb(player_pos); - glm::vec3 min = player_box.min(); - glm::vec3 max = player_box.max(); - - int minx = std::floor(min.x); - int maxx = std::floor(max.x); - int miny = std::floor(min.y); - int maxy = std::floor(max.y); - int minz = std::floor(min.z); - int maxz = std::floor(max.z); - - for (int x = minx; x <= maxx; ++x) { - for (int y = miny; y <= maxy; ++y) { - for (int z = minz; z <= maxz; ++z) { - glm::ivec3 block_pos{x, y, z}; - if (!m_world.can_pass_block(block_pos)) { - AABB block_box = ClientWorld::get_block_aabb(block_pos); - if (player_box.intersects(block_box)) { - player_pos.y -= move_distance.y; - m_velocity.value.y = 0.0f; - if (move_distance.y < 0) { - m_move_state.can_up = true; - m_move_state.is_fly = false; - } - return; - } - } - } - } - } -} - -void ClientPlayer::update_z_move(glm::vec3& player_pos) { - player_pos.z += move_distance.z; - if (m_game_mode == SPECTATOR) { - return; - } - AABB player_box = get_aabb(player_pos); - glm::vec3 min = player_box.min(); - glm::vec3 max = player_box.max(); - - int minx = std::floor(min.x); - int maxx = std::floor(max.x); - int miny = std::floor(min.y); - int maxy = std::floor(max.y); - int minz = std::floor(min.z); - int maxz = std::floor(max.z); - - for (int x = minx; x <= maxx; ++x) { - for (int y = miny; y <= maxy; ++y) { - for (int z = minz; z <= maxz; ++z) { - glm::ivec3 block_pos{x, y, z}; - if (!m_world.can_pass_block(block_pos)) { - AABB block_box = ClientWorld::get_block_aabb(block_pos); - if (player_box.intersects(block_box)) { - m_sprinting = false; - player_pos.z -= move_distance.z; - return; - } - } - } - } - } -} - void ClientPlayer::update_player_chunk() { float x, z; { diff --git a/src/gameplay/client_world.cpp b/src/gameplay/client_world.cpp index f8c02cf..58ca240 100644 --- a/src/gameplay/client_world.cpp +++ b/src/gameplay/client_world.cpp @@ -4,6 +4,7 @@ #include "Cubed/gameplay/chunk_generator.hpp" #include "Cubed/gameplay/entity.hpp" #include "Cubed/gameplay/game_time.hpp" +#include "Cubed/gameplay/hitbox_manager.hpp" #include "Cubed/gameplay/packet.hpp" #include "Cubed/scene/world_scene.hpp" #include "Cubed/tools/math_tools.hpp" @@ -299,7 +300,8 @@ void ClientWorld::report_block_change(const glm::ivec3& pos, for (const auto& player : m_players_data) { - AABB box = ClientPlayer::get_aabb(player.pos.value); + AABB box = HitboxManager::aabb("cubed:player"); + box.center += player.pos.value; if (box.intersects(block_box)) { return; } diff --git a/src/gameplay/entity.cpp b/src/gameplay/entity.cpp index 1b9b550..7ea7030 100644 --- a/src/gameplay/entity.cpp +++ b/src/gameplay/entity.cpp @@ -20,4 +20,14 @@ Movement& Entity::movement() { return m_movement; } Gravity& Entity::gravity() { return m_gravity; } MoveState& Entity::move_state() { return m_move_state; } Direction& Entity::direction() { return m_direction; } + +const Velocity& Entity::velocity() const { return m_velocity; } +const Position& Entity::pos() const { return m_pos; } +const WalkPose& Entity::walk_pose() const { return m_walk_pose; } +const Orientation& Entity::angle() const { return m_angle; } +const Movement& Entity::movement() const { return m_movement; } +const Gravity& Entity::gravity() const { return m_gravity; } +const MoveState& Entity::move_state() const { return m_move_state; } +const Direction& Entity::direction() const { return m_direction; } + } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/hitbox_manager.cpp b/src/gameplay/hitbox_manager.cpp index 49c7b76..a340709 100644 --- a/src/gameplay/hitbox_manager.cpp +++ b/src/gameplay/hitbox_manager.cpp @@ -1,12 +1,20 @@ #include "Cubed/gameplay/hitbox_manager.hpp" +#include "Cubed/gameplay/player.hpp" #include "Cubed/tools/log.hpp" #include namespace fs = std::filesystem; using nlohmann::json; namespace Cubed { -HitboxManager::HitboxManager() {} +HitboxManager::HitboxManager() { + + glm::vec3 half = PLAYER_SIZE * 0.5f; + + glm::vec3 center{0.0f, half.y, 0.0f}; + m_hitboxes.emplace("cubed:player", AABB{center, half}); +} + HitboxManager::~HitboxManager() {} HitboxManager& HitboxManager::instance() { diff --git a/src/gameplay/systems/physical_system.cpp b/src/gameplay/systems/physical_system.cpp new file mode 100644 index 0000000..ed126d4 --- /dev/null +++ b/src/gameplay/systems/physical_system.cpp @@ -0,0 +1,154 @@ +#include "Cubed/gameplay/systems/physical_system.hpp" + +#include "Cubed/gameplay/hitbox_manager.hpp" +namespace Cubed { + +namespace { + +bool update_x(const glm::vec3& pos, const glm::vec3& distance, World& world, + const AABB& box) { + glm::vec3 p = pos; + p.x += distance.x; + AABB b = box; + b.center += p; + glm::vec3 min = b.min(); + glm::vec3 max = b.max(); + int minx = std::floor(min.x); + int maxx = std::floor(max.x); + int miny = std::floor(min.y); + int maxy = std::floor(max.y); + int minz = std::floor(min.z); + int maxz = std::floor(max.z); + + for (int x = minx; x <= maxx; ++x) { + for (int y = miny; y <= maxy; ++y) { + for (int z = minz; z <= maxz; ++z) { + glm::ivec3 block_pos{x, y, z}; + if (!world.can_pass_block(block_pos)) { + AABB block_box = World::get_block_aabb(block_pos); + if (b.intersects(block_box)) { + return false; + } + } + } + } + } + return true; +} + +bool update_y(const glm::vec3& pos, const glm::vec3& distance, World& world, + const AABB& box) { + glm::vec3 p = pos; + p.y += distance.y; + AABB b = box; + b.center += p; + glm::vec3 min = b.min(); + glm::vec3 max = b.max(); + int minx = std::floor(min.x); + int maxx = std::floor(max.x); + int miny = std::floor(min.y); + int maxy = std::floor(max.y); + int minz = std::floor(min.z); + int maxz = std::floor(max.z); + + for (int x = minx; x <= maxx; ++x) { + for (int y = miny; y <= maxy; ++y) { + for (int z = minz; z <= maxz; ++z) { + glm::ivec3 block_pos{x, y, z}; + if (!world.can_pass_block(block_pos)) { + AABB block_box = World::get_block_aabb(block_pos); + if (b.intersects(block_box)) { + return false; + } + } + } + } + } + return true; +} + +bool update_z(const glm::vec3& pos, const glm::vec3& distance, World& world, + const AABB& box) { + glm::vec3 p = pos; + p.z += distance.z; + AABB b = box; + b.center += p; + glm::vec3 min = b.min(); + glm::vec3 max = b.max(); + int minx = std::floor(min.x); + int maxx = std::floor(max.x); + int miny = std::floor(min.y); + int maxy = std::floor(max.y); + int minz = std::floor(min.z); + int maxz = std::floor(max.z); + + for (int x = minx; x <= maxx; ++x) { + for (int y = miny; y <= maxy; ++y) { + for (int z = minz; z <= maxz; ++z) { + glm::ivec3 block_pos{x, y, z}; + if (!world.can_pass_block(block_pos)) { + AABB block_box = World::get_block_aabb(block_pos); + if (b.intersects(block_box)) { + return false; + } + } + } + } + } + return true; +} + +} // namespace +std::tuple PhysicalSystem::update(float dt, Entity& e, + World& world) { + glm::vec3 pos = e.pos().value; + auto ans = update(dt, e, world, pos); + e.pos().value = pos; + return ans; +} + +std::tuple PhysicalSystem::update(float dt, Entity& e, + World& world, + glm::vec3& moved_pos) { + auto distance = get_move_distance(dt, e); + auto& m_velocity = e.velocity(); + auto& m_move_state = e.move_state(); + AABB box = HitboxManager::aabb("cubed:player"); + bool x = false; + bool y = false; + bool z = false; + if (update_x(moved_pos, distance, world, box)) { + moved_pos.x += distance.x; + x = true; + } else { + m_velocity.value.x = 0.0f; + } + + if (update_y(moved_pos, distance, world, box)) { + moved_pos.y += distance.y; + y = true; + } else { + m_velocity.value.y = 0.0f; + if (distance.y < 0) { + m_move_state.can_up = true; + m_move_state.is_fly = false; + } + } + + if (update_z(moved_pos, distance, world, box)) { + moved_pos.z += distance.z; + z = true; + } else { + m_velocity.value.z = 0.0f; + } + return {x, y, z}; +} + +glm::vec3 PhysicalSystem::get_move_distance(float dt, const Entity& e) { + auto& m_direction = e.direction(); + auto& m_velocity = e.velocity(); + return glm::vec3{m_direction.value.x * m_velocity.value.x * dt, + m_velocity.value.y * dt, + m_direction.value.z * m_velocity.value.z * dt}; +} +} // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/systems/speed_system.cpp b/src/gameplay/systems/speed_system.cpp new file mode 100644 index 0000000..03e09c9 --- /dev/null +++ b/src/gameplay/systems/speed_system.cpp @@ -0,0 +1,56 @@ +#include "Cubed/gameplay/systems/speed_system.hpp" + +namespace Cubed { +void SpeedSystem::update(float dt, Entity& e) { + auto& m_velocity = e.velocity(); + auto& m_move_state = e.move_state(); + auto& m_movement = e.movement(); + auto& direction = e.direction(); + auto& m_gravity = e.gravity(); + // calculate speed + if (m_move_state.forward || m_move_state.back || m_move_state.left || + m_move_state.right) { + direction.value = glm::vec3(0.0f, 0.0f, 0.0f); + m_velocity.value.x += m_movement.acceleration * dt; + m_velocity.value.z += m_movement.acceleration * dt; + if (m_velocity.value.x > m_velocity.max.x) { + m_velocity.value.x = m_velocity.max.x; + } + if (m_velocity.value.z > m_velocity.max.z) { + m_velocity.value.z = m_velocity.max.z; + } + } else { + m_velocity.value.x += -m_movement.deceleration * dt; + m_velocity.value.z += -m_movement.deceleration * dt; + if (m_velocity.value.z < 0.0f) { + m_velocity.value.z = 0.0f; + } + if (m_velocity.value.x < 0.0f) { + m_velocity.value.x = 0.0f; + } + if (m_velocity.value.z < 0.0f && m_velocity.value.x < 0.0f) { + direction.value = glm::vec3(0.0f, 0.0f, 0.0f); + } + } + if (m_move_state.is_fly) { + if (m_move_state.up) { + m_velocity.value.y = m_velocity.max.y; + } + + if (m_move_state.down) { + m_velocity.value.y = -m_velocity.max.y; + } + + if (!m_move_state.down && !m_move_state.up) { + m_velocity.value.y = 0.0f; + } + } else { + if (m_move_state.up && m_move_state.can_up) { + m_velocity.value.y = m_movement.jump_power; + m_move_state.can_up = false; + } + + m_velocity.value.y += -m_gravity.value * dt; + } +} +} // namespace Cubed \ No newline at end of file