refactor: move movement logic into SpeedSystem and Entity components

This commit is contained in:
2026-07-28 10:54:13 +08:00
parent 831569cec6
commit bd1a9557a5
9 changed files with 145 additions and 100 deletions

View File

@@ -65,7 +65,7 @@ public:
void set_uuid(std::string_view uuid); void set_uuid(std::string_view uuid);
std::string get_uuid() const; std::string get_uuid() const;
const std::string& get_name() const; const std::string& get_name() const;
void reset_key_status(); void reset_input_status();
void init(std::string_view name); void init(std::string_view name);
bool ray_cast(const glm::vec3& start, const glm::vec3& dir, bool ray_cast(const glm::vec3& start, const glm::vec3& dir,
@@ -83,7 +83,7 @@ private:
using enum GameMode; using enum GameMode;
float m_max_walk_speed = DEFAULT_MAX_WALK_SPEED; float m_max_walk_speed = DEFAULT_MAX_WALK_SPEED;
float m_max_run_speed = DEFAULT_MAX_RUN_SPEED; float m_max_run_speed = DEFAULT_MAX_RUN_SPEED;
float m_max_y_speed = 7.5f;
static constexpr float MAX_SPACE_ON_TIME = 0.3f; static constexpr float MAX_SPACE_ON_TIME = 0.3f;
static constexpr float PLACE_BLOCK_INTERVAL = 0.2f; static constexpr float PLACE_BLOCK_INTERVAL = 0.2f;
Movement m_movement{}; Movement m_movement{};
@@ -93,12 +93,8 @@ private:
std::array<ItemStack, HOTBAR_SUM> m_hotbar; std::array<ItemStack, HOTBAR_SUM> m_hotbar;
float m_sensitivity = 0.15f; float m_sensitivity = 0.15f;
float m_fly_y_speed = 7.5f;
bool can_up = true;
float space_on_time = 0.0f; float space_on_time = 0.0f;
bool space_on = false; bool space_on = false;
bool is_fly = false;
int m_selected_hotbar = 0; int m_selected_hotbar = 0;
@@ -106,7 +102,6 @@ private:
bool m_sprinting = false; bool m_sprinting = false;
bool m_underwater = false; bool m_underwater = false;
glm::vec3 direction = glm::vec3(0.0f, 0.0f, 0.0f);
glm::vec3 move_distance{0.0f, 0.0f, 0.0f}; glm::vec3 move_distance{0.0f, 0.0f, 0.0f};
// player is tow block tall, the pos is the lower pos // player is tow block tall, the pos is the lower pos
ChunkPos m_last_chunk_pos{0, 0}; ChunkPos m_last_chunk_pos{0, 0};
@@ -115,7 +110,6 @@ private:
glm::vec3 m_right{0, 0, 0}; glm::vec3 m_right{0, 0, 0};
static constexpr glm::vec3 M_SIZE{0.6f, 1.8f, 0.6f}; static constexpr glm::vec3 M_SIZE{0.6f, 1.8f, 0.6f};
MoveState m_move_state{};
MouseState m_mouse_state{}; MouseState m_mouse_state{};
GameMode m_game_mode = CREATIVE; GameMode m_game_mode = CREATIVE;
std::optional<LookBlock> m_look_block = std::nullopt; std::optional<LookBlock> m_look_block = std::nullopt;

View File

@@ -37,7 +37,7 @@ struct Orientation {
struct Velocity { struct Velocity {
glm::vec3 value{0.0f}; glm::vec3 value{0.0f};
glm::vec3 max{4.5f}; glm::vec3 max{4.5f, 7.5f, 7.5f};
}; };
struct HitBoxes { struct HitBoxes {
@@ -54,6 +54,22 @@ struct Gravity {
float value = DEFAULT_G; float value = DEFAULT_G;
}; };
struct MoveState {
bool forward = false;
bool back = false;
bool left = false;
bool right = false;
bool down = false;
bool up = false;
bool is_fly = false;
bool can_up = true;
};
struct Direction {
glm::vec3 value{0.0f};
};
class Entity { class Entity {
public: public:
glm::vec3& max_speed(); glm::vec3& max_speed();
@@ -67,13 +83,24 @@ public:
float& walk_time(); float& walk_time();
Gait get_gait() const; Gait get_gait() const;
Velocity& velocity();
Position& pos();
WalkPose& walk_pose();
Orientation& angle();
Movement& movement();
Gravity& gravity();
MoveState& move_state();
Direction& direction();
protected: protected:
Position m_pos; Position m_pos;
WalkPose m_walk_pos; WalkPose m_walk_pose;
Velocity m_velocity; Velocity m_velocity;
Orientation m_angle; Orientation m_angle;
Movement m_movement; Movement m_movement;
Gravity m_gravity; Gravity m_gravity;
MoveState m_move_state;
Direction m_direction;
}; };
} // namespace Cubed } // namespace Cubed

View File

@@ -0,0 +1,63 @@
#pragma once
#include "Cubed/gameplay/entity.hpp"
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;
}
}
private:
};
} // namespace Cubed

View File

@@ -2,15 +2,6 @@
namespace Cubed { namespace Cubed {
struct MoveState {
bool forward = false;
bool back = false;
bool left = false;
bool right = false;
bool down = false;
bool up = false;
};
struct MouseState { struct MouseState {
bool left = false; bool left = false;
bool right = false; bool right = false;

View File

@@ -516,6 +516,7 @@ void DevPanel::show_player_tab_item() {
m_player->deceleration() = DEFAULT_DECELERATION; m_player->deceleration() = DEFAULT_DECELERATION;
m_player->g() = DEFAULT_G; m_player->g() = DEFAULT_G;
m_player->change_mode(GameMode::CREATIVE); m_player->change_mode(GameMode::CREATIVE);
m_player->fly_y_speed() = 7.5f;
m_player->set_gait(Gait::WALK); m_player->set_gait(Gait::WALK);
m_player_profile.game_mode = 0; m_player_profile.game_mode = 0;
m_player_profile.gait = 0; m_player_profile.gait = 0;

View File

@@ -4,7 +4,7 @@
#include "Cubed/config.hpp" #include "Cubed/config.hpp"
#include "Cubed/debug_collector.hpp" #include "Cubed/debug_collector.hpp"
#include "Cubed/gameplay/client_world.hpp" #include "Cubed/gameplay/client_world.hpp"
#include "Cubed/gameplay/systems/speed_system.hpp"
namespace {} // namespace namespace {} // namespace
namespace Cubed { namespace Cubed {
@@ -108,13 +108,15 @@ void ClientPlayer::change_mode(GameMode mode) {
m_game_mode = mode; m_game_mode = mode;
Logger::info("Change GameMode to {}", to_str(mode)); Logger::info("Change GameMode to {}", to_str(mode));
if (mode == CREATIVE) { if (mode == CREATIVE) {
is_fly = false; m_move_state.is_fly = false;
m_max_run_speed = DEFAULT_MAX_RUN_SPEED; m_max_run_speed = DEFAULT_MAX_RUN_SPEED;
m_velocity.max = glm::vec3{m_max_walk_speed, 0.0f, m_max_walk_speed}; m_velocity.max =
glm::vec3{m_max_walk_speed, m_max_y_speed, m_max_walk_speed};
} else if (mode == SPECTATOR) { } else if (mode == SPECTATOR) {
is_fly = true; m_move_state.is_fly = true;
m_walk_pos.gait = Gait::RUN; m_walk_pose.gait = Gait::RUN;
m_velocity.max = glm::vec3{m_max_run_speed, 0.0f, m_max_run_speed}; m_velocity.max =
glm::vec3{m_max_run_speed, m_max_y_speed, m_max_run_speed};
} }
} }
void ClientPlayer::reload_config() { void ClientPlayer::reload_config() {
@@ -128,9 +130,9 @@ void ClientPlayer::set_player_pos(const glm::vec3& pos) {
} }
void ClientPlayer::update(float delta_time) { void ClientPlayer::update(float delta_time) {
WalkPose pos = m_walk_pos; WalkPose pos = m_walk_pose;
pos.gait = compute_gait(); pos.gait = compute_gait();
m_walk_pos = pos; m_walk_pose = pos;
update_move(delta_time); update_move(delta_time);
update_lookup_block(); update_lookup_block();
place_block(delta_time); place_block(delta_time);
@@ -175,7 +177,7 @@ bool ClientPlayer::update_player_move_state(Key key, KeyAction action) {
m_move_state.up = true; m_move_state.up = true;
if (space_on) { if (space_on) {
if (m_game_mode == CREATIVE) { if (m_game_mode == CREATIVE) {
is_fly = !is_fly; m_move_state.is_fly = !m_move_state.is_fly;
m_velocity.value.y = 0.0f; m_velocity.value.y = 0.0f;
} }
space_on = false; space_on = false;
@@ -277,7 +279,7 @@ void ClientPlayer::update_direction() {
move_dir = move_dir_front + move_dir_right; move_dir = move_dir_front + move_dir_right;
if (glm::length(move_dir) > 0.001f) { if (glm::length(move_dir) > 0.001f) {
direction = glm::normalize(move_dir); m_direction.value = glm::normalize(move_dir);
} }
} }
@@ -340,26 +342,10 @@ void ClientPlayer::update_move(float delta_time) {
if (delta_time > 1.0f) { if (delta_time > 1.0f) {
return; return;
} }
if (m_velocity.value.x < 0.01f || m_velocity.value.z < 0.01f) { if (m_velocity.value.x < 0.01f || m_velocity.value.z < 0.01f) {
m_sprinting = false; m_sprinting = false;
} }
// ensure the thread safe
glm::vec3 player_pos;
{
std::shared_lock lock(m_player_pos_mutex);
player_pos = m_pos.value;
}
if (m_game_mode != SPECTATOR) {
m_velocity.max =
(m_walk_pos.gait == Gait::RUN)
? glm::vec3{m_max_run_speed, 0.0f, m_max_run_speed}
: glm::vec3{m_max_walk_speed, 0.0f, m_max_walk_speed};
} else {
m_velocity.max = glm::vec3{m_max_run_speed, 0.0f, m_max_run_speed};
}
if (space_on) { if (space_on) {
space_on_time += delta_time; space_on_time += delta_time;
if (space_on_time >= MAX_SPACE_ON_TIME) { if (space_on_time >= MAX_SPACE_ON_TIME) {
@@ -368,59 +354,33 @@ void ClientPlayer::update_move(float delta_time) {
} }
} }
// calculate speed if (m_game_mode != SPECTATOR) {
if (m_move_state.forward || m_move_state.back || m_move_state.left || m_velocity.max =
m_move_state.right) { (m_walk_pose.gait == Gait::RUN)
direction = glm::vec3(0.0f, 0.0f, 0.0f); ? glm::vec3{m_max_run_speed, m_max_y_speed, m_max_run_speed}
m_velocity.value.x += m_movement.acceleration * delta_time; : glm::vec3{m_max_walk_speed, m_max_y_speed, m_max_walk_speed};
m_velocity.value.z += m_movement.acceleration * delta_time;
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 { } else {
m_velocity.value.x += -m_movement.deceleration * delta_time; m_velocity.max =
m_velocity.value.z += -m_movement.deceleration * delta_time; glm::vec3{m_max_run_speed, m_max_y_speed, m_max_run_speed};
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 = glm::vec3(0.0f, 0.0f, 0.0f);
}
} }
SpeedSystem::update(delta_time, *this);
update_direction(); update_direction();
move_distance = {direction.x * m_velocity.value.x * delta_time, 0.0f, move_distance = {m_direction.value.x * m_velocity.value.x * delta_time,
direction.z * m_velocity.value.z * delta_time}; 0.0f,
m_direction.value.z * m_velocity.value.z * delta_time};
move_distance.y = m_velocity.value.y * delta_time;
if (is_fly) { // ensure the thread safe
if (m_move_state.up) { glm::vec3 player_pos;
m_velocity.value.y = m_fly_y_speed;
}
if (m_move_state.down) { {
m_velocity.value.y = -m_fly_y_speed; std::shared_lock lock(m_player_pos_mutex);
} player_pos = m_pos.value;
if (!m_move_state.down && !m_move_state.up) {
m_velocity.value.y = 0.0f;
}
} else {
if (m_move_state.up && can_up) {
m_velocity.value.y = m_movement.jump_power;
can_up = false;
}
m_velocity.value.y += -m_gravity.value * delta_time;
} }
move_distance.y = m_velocity.value.y * delta_time;
// y // y
update_y_move(player_pos); update_y_move(player_pos);
// x // x
@@ -512,8 +472,8 @@ void ClientPlayer::update_y_move(glm::vec3& player_pos) {
player_pos.y -= move_distance.y; player_pos.y -= move_distance.y;
m_velocity.value.y = 0.0f; m_velocity.value.y = 0.0f;
if (move_distance.y < 0) { if (move_distance.y < 0) {
can_up = true; m_move_state.can_up = true;
is_fly = false; m_move_state.is_fly = false;
} }
return; return;
} }
@@ -669,7 +629,7 @@ ClientPlayer::ChunkPosSet ClientPlayer::get_chunk_pos_set() {
float& ClientPlayer::max_walk_speed() { return m_max_walk_speed; } float& ClientPlayer::max_walk_speed() { return m_max_walk_speed; }
float& ClientPlayer::max_run_speed() { return m_max_run_speed; } float& ClientPlayer::max_run_speed() { return m_max_run_speed; }
float& ClientPlayer::fly_y_speed() { return m_fly_y_speed; } float& ClientPlayer::fly_y_speed() { return m_max_y_speed; }
const ItemStack& ClientPlayer::get_current_itemstack() const { const ItemStack& ClientPlayer::get_current_itemstack() const {
return m_hotbar[m_selected_hotbar]; return m_hotbar[m_selected_hotbar];
}; };
@@ -688,7 +648,7 @@ std::string ClientPlayer::get_uuid() const {
} }
const std::string& ClientPlayer::get_name() const { return m_name; } const std::string& ClientPlayer::get_name() const { return m_name; }
void ClientPlayer::reset_key_status() { void ClientPlayer::reset_input_status() {
m_mouse_state.left = false; m_mouse_state.left = false;
m_mouse_state.right = false; m_mouse_state.right = false;
m_move_state.left = false; m_move_state.left = false;
@@ -708,7 +668,7 @@ void ClientPlayer::init(std::string_view name) {
m_name = name; m_name = name;
m_timers.try_emplace("Player Walk Sound", WALK_SOUND_INTERVAL, [this]() { m_timers.try_emplace("Player Walk Sound", WALK_SOUND_INTERVAL, [this]() {
if (!m_moving || is_fly) { if (!m_moving || m_move_state.is_fly) {
return; return;
} }
glm::ivec3 block; glm::ivec3 block;

View File

@@ -692,7 +692,7 @@ void ClientWorld::request_chunk() {
Logger::info("Send Chunk Request Success"); Logger::info("Send Chunk Request Success");
m_requesting_chunk = false; m_requesting_chunk = false;
} }
void ClientWorld::reset_key_status() { m_player.reset_key_status(); } void ClientWorld::reset_key_status() { m_player.reset_input_status(); }
void ClientWorld::receive_chunk(std::vector<uint8_t> raw_data, void ClientWorld::receive_chunk(std::vector<uint8_t> raw_data,
PacketHeader header) { PacketHeader header) {

View File

@@ -5,10 +5,19 @@ glm::vec3& Entity::max_speed() { return m_velocity.max; }
float& Entity::acceleration() { return m_movement.acceleration; } float& Entity::acceleration() { return m_movement.acceleration; }
float& Entity::deceleration() { return m_movement.deceleration; } float& Entity::deceleration() { return m_movement.deceleration; }
float& Entity::g() { return m_gravity.value; } float& Entity::g() { return m_gravity.value; }
void Entity::set_gait(Gait gait) { m_walk_pos.gait = gait; } void Entity::set_gait(Gait gait) { m_walk_pose.gait = gait; }
float Entity::yaw() const { return m_angle.yaw; } float Entity::yaw() const { return m_angle.yaw; }
float Entity::pitch() const { return m_angle.pitch; } float Entity::pitch() const { return m_angle.pitch; }
float& Entity::roll() { return m_angle.roll; } float& Entity::roll() { return m_angle.roll; }
float& Entity::walk_time() { return m_walk_pos.walk_time; } float& Entity::walk_time() { return m_walk_pose.walk_time; }
Gait Entity::get_gait() const { return m_walk_pos.gait; } Gait Entity::get_gait() const { return m_walk_pose.gait; }
Velocity& Entity::velocity() { return m_velocity; }
Position& Entity::pos() { return m_pos; }
WalkPose& Entity::walk_pose() { return m_walk_pose; }
Orientation& Entity::angle() { return m_angle; }
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; }
} // namespace Cubed } // namespace Cubed

View File

@@ -330,7 +330,7 @@ void Window::set_imgui_enabled(bool enable) {
if (m_camera) { if (m_camera) {
auto player = m_camera->player(); auto player = m_camera->player();
if (player) { if (player) {
player->reset_key_status(); player->reset_input_status();
} }
} }
} }