feat(client-player): add block cooldown and track mouse state

Introduce a time-based cooldown for block placement (PLACE_BLOCK_INTERVAL) to prevent rapid clicking. Replace the global InputState with per-player MouseState tracking in ClientPlayer. Rename place_block() to get_current_block() for clarity. Remove the old src/input.cpp and the Cubed/input.hpp header, moving input structures to Cubed/input/input.hpp.
This commit is contained in:
2026-07-12 21:03:50 +08:00
parent 674c023228
commit 8bbed7b7b9
6 changed files with 39 additions and 46 deletions

View File

@@ -6,8 +6,8 @@
#include "Cubed/gameplay/game_mode.hpp" #include "Cubed/gameplay/game_mode.hpp"
#include "Cubed/gameplay/game_time.hpp" #include "Cubed/gameplay/game_time.hpp"
#include "Cubed/gameplay/player.hpp" #include "Cubed/gameplay/player.hpp"
#include "Cubed/input.hpp"
#include "Cubed/input/event.hpp" #include "Cubed/input/event.hpp"
#include "Cubed/input/input.hpp"
#include <absl/container/flat_hash_set.h> #include <absl/container/flat_hash_set.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
@@ -58,7 +58,7 @@ public:
float& g(); float& g();
float& fly_y_speed(); float& fly_y_speed();
unsigned place_block() const; unsigned get_current_block() const;
void set_gait(Gait gait); void set_gait(Gait gait);
GameMode& game_mode(); GameMode& game_mode();
@@ -80,6 +80,7 @@ public:
float distance = 4.0f); float distance = 4.0f);
bool is_underwater() const; bool is_underwater() const;
void set_underwater(bool u); void set_underwater(bool u);
void place_block(float dt);
private: private:
using enum GameMode; using enum GameMode;
@@ -89,7 +90,8 @@ private:
float m_deceleration = DEFAULT_DECELERATION; float m_deceleration = DEFAULT_DECELERATION;
float m_g = DEFAULT_G; float m_g = DEFAULT_G;
constexpr static float MAX_SPACE_ON_TIME = 0.3f; constexpr static float MAX_SPACE_ON_TIME = 0.3f;
constexpr static float PLACE_BLOCK_INTERVAL = 0.2f;
float m_place_time = PLACE_BLOCK_INTERVAL;
std::atomic<float> m_yaw = 0.0f; std::atomic<float> m_yaw = 0.0f;
std::atomic<float> m_pitch = 0.0f; std::atomic<float> m_pitch = 0.0f;
@@ -125,6 +127,7 @@ private:
std::atomic<Gait> m_gait = Gait::STOP; std::atomic<Gait> m_gait = Gait::STOP;
MoveState m_move_state{}; MoveState m_move_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;
std::string m_name{}; std::string m_name{};
@@ -144,8 +147,6 @@ private:
void update_direction(); void update_direction();
void update_lookup_block(); void update_lookup_block();
bool place_block(MouseKey key);
void update_move(float delta_time); void update_move(float delta_time);
void update_x_move(glm::vec3& player_pos); void update_x_move(glm::vec3& player_pos);

View File

@@ -18,19 +18,4 @@ struct MouseState {
bool right = false; bool right = false;
}; };
struct KeyState {
bool r = false;
};
struct InputState {
MoveState move_state;
MouseState mouse_state;
KeyState key_state;
};
namespace Input {
InputState& get_input_state();
}
} // namespace Cubed } // namespace Cubed

View File

@@ -9,7 +9,6 @@ target_sources(${PROJECT_NAME}
gameplay/biome.cpp gameplay/biome.cpp
gameplay/chunk_generator.cpp gameplay/chunk_generator.cpp
gameplay/tree.cpp gameplay/tree.cpp
input.cpp
render/renderer.cpp render/renderer.cpp
shader.cpp shader.cpp
texture_manager.cpp texture_manager.cpp

View File

@@ -655,7 +655,7 @@ void DevPanel::show_items_tab_item() {
if (ImGui::BeginTabItem("item")) { if (ImGui::BeginTabItem("item")) {
ImGui::Text("Place Block "); ImGui::Text("Place Block ");
ImGui::SameLine(); ImGui::SameLine();
auto& place_texture = textures[m_player->place_block()]; auto& place_texture = textures[m_player->get_current_block()];
if (place_texture) { if (place_texture) {
ImGui::Image(static_cast<ImTextureID>( ImGui::Image(static_cast<ImTextureID>(
static_cast<intptr_t>(place_texture->id())), static_cast<intptr_t>(place_texture->id())),

View File

@@ -132,7 +132,7 @@ void ClientPlayer::update(float delta_time) {
m_gait = compute_gait(); m_gait = compute_gait();
update_move(delta_time); update_move(delta_time);
update_lookup_block(); update_lookup_block();
place_block(delta_time);
DebugCollector::get().report("player_pos", DebugCollector::get().report("player_pos",
std::format("x: {:.2f} y: {:.2f} z: {:.2f}", std::format("x: {:.2f} y: {:.2f} z: {:.2f}",
m_player_pos.x, m_player_pos.y, m_player_pos.x, m_player_pos.y,
@@ -274,30 +274,32 @@ void ClientPlayer::update_lookup_block() {
m_look_block = std::nullopt; m_look_block = std::nullopt;
} }
} }
bool ClientPlayer::place_block(MouseKey key) { void ClientPlayer::place_block(float dt) {
if (m_look_block == std::nullopt) { if (m_look_block == std::nullopt) {
return false; return;
} }
bool placeed = false; m_place_time += dt;
if (key == MouseKey::LEFT_BUTTON) { if (m_place_time < PLACE_BLOCK_INTERVAL) {
return;
}
m_place_time = 0.0f;
if (m_mouse_state.left) {
if (m_world.is_solid(m_look_block->pos)) { if (m_world.is_solid(m_look_block->pos)) {
m_world.report_block_change(m_look_block->pos, 0); m_world.report_block_change(m_look_block->pos, 0);
placeed = true;
} }
} }
if (key == MouseKey::RIGHT_BUTTON) { if (m_mouse_state.right) {
glm::ivec3 near_pos = m_look_block->pos + m_look_block->normal; glm::ivec3 near_pos = m_look_block->pos + m_look_block->normal;
if (!m_world.is_solid(near_pos)) { if (!m_world.is_solid(near_pos)) {
AABB block_box = ClientWorld::get_block_aabb(near_pos); AABB block_box = ClientWorld::get_block_aabb(near_pos);
AABB player_box = get_aabb(get_player_pos()); AABB player_box = get_aabb(get_player_pos());
if (!player_box.intersects(block_box)) { if (!player_box.intersects(block_box)) {
m_world.report_block_change(near_pos, m_place_block); m_world.report_block_change(near_pos, m_place_block);
placeed = true;
} }
} }
} }
return placeed;
} }
void ClientPlayer::update_move(float delta_time) { void ClientPlayer::update_move(float delta_time) {
// if frame rate less than 1 frame per second, don't update // if frame rate less than 1 frame per second, don't update
@@ -555,7 +557,26 @@ bool ClientPlayer::update_scroll(float yoffset) {
bool ClientPlayer::handle_mouse_button_event(const MouseButtonEvent& e) { bool ClientPlayer::handle_mouse_button_event(const MouseButtonEvent& e) {
if (e.action == KeyAction::PRESS) { if (e.action == KeyAction::PRESS) {
return place_block(e.key); if (e.key == MouseKey::LEFT_BUTTON) {
m_mouse_state.left = true;
m_place_time = PLACE_BLOCK_INTERVAL;
return true;
}
if (e.key == MouseKey::RIGHT_BUTTON) {
m_mouse_state.right = true;
m_place_time = PLACE_BLOCK_INTERVAL;
return true;
}
}
if (e.action == KeyAction::RELEASE) {
if (e.key == MouseKey::LEFT_BUTTON) {
m_mouse_state.left = false;
return true;
}
if (e.key == MouseKey::RIGHT_BUTTON) {
m_mouse_state.right = false;
return true;
}
} }
return false; return false;
} }
@@ -597,7 +618,7 @@ float& ClientPlayer::acceleration() { return m_acceleration; }
float& ClientPlayer::deceleration() { return m_deceleration; } float& ClientPlayer::deceleration() { return m_deceleration; }
float& ClientPlayer::g() { return m_g; } float& ClientPlayer::g() { return m_g; }
float& ClientPlayer::fly_y_speed() { return m_fly_y_speed; } float& ClientPlayer::fly_y_speed() { return m_fly_y_speed; }
unsigned ClientPlayer::place_block() const { return m_place_block; }; unsigned ClientPlayer::get_current_block() const { return m_place_block; };
void ClientPlayer::set_gait(Gait gait) { m_gait = gait; } void ClientPlayer::set_gait(Gait gait) { m_gait = gait; }
GameMode& ClientPlayer::game_mode() { return m_game_mode; } GameMode& ClientPlayer::game_mode() { return m_game_mode; }
ClientWorld& ClientPlayer::get_world() { return m_world; } ClientWorld& ClientPlayer::get_world() { return m_world; }

View File

@@ -1,13 +0,0 @@
#include "Cubed/input.hpp"
namespace Cubed {
static InputState input_state;
namespace Input {
InputState& get_input_state() { return input_state; }
} // namespace Input
} // namespace Cubed