diff --git a/include/Cubed/constants.hpp b/include/Cubed/constants.hpp index cc3fc14..48ec76c 100644 --- a/include/Cubed/constants.hpp +++ b/include/Cubed/constants.hpp @@ -16,6 +16,11 @@ constexpr int PRE_LOAD_DISTANCE = 24; constexpr int MAX_DISTANCE = 128; constexpr float DEFAULT_FOV = 70.0f; +constexpr float DEFAULT_MAX_WALK_SPEED = 4.5f; +constexpr float DEFAULT_MAX_RUN_SPEED = 7.0f; +constexpr float DEFAULT_ACCELERATION = 10.0f; +constexpr float DEFAULT_DECELERATION = 15.0f; +constexpr float DEFAULT_G = 22.5f; using HeightMapArray = std::array, CHUCK_SIZE>; diff --git a/include/Cubed/dev_panel.hpp b/include/Cubed/dev_panel.hpp index 2ec7ca1..fa2e793 100644 --- a/include/Cubed/dev_panel.hpp +++ b/include/Cubed/dev_panel.hpp @@ -16,6 +16,13 @@ class DevPanel { int height; int rendering_distance; }; + struct PlayerProfile { + int game_mode = 0; + int gait = 0; + }; + struct TextEditing { + bool perlin_seed = false; + }; public: DevPanel(App& app); void init(); @@ -25,12 +32,16 @@ private: App& m_app; ConfigView m_config; Player* m_player; - + PlayerProfile m_player_profile; + TextEditing m_text_editing; bool m_need_save_config = false; int m_theme = 0; void show_settings_tab_item(); void show_world_tab_item(); void show_player_tab_item(); + + void update_player_profile(); + }; diff --git a/include/Cubed/gameplay/game_mode.hpp b/include/Cubed/gameplay/game_mode.hpp index bb8d145..ed2d5b6 100644 --- a/include/Cubed/gameplay/game_mode.hpp +++ b/include/Cubed/gameplay/game_mode.hpp @@ -7,7 +7,7 @@ namespace Cubed { enum class GameMode { - CREATIVE, + CREATIVE = 0, SPECTATOR }; diff --git a/include/Cubed/gameplay/player.hpp b/include/Cubed/gameplay/player.hpp index 1171f75..57e1567 100644 --- a/include/Cubed/gameplay/player.hpp +++ b/include/Cubed/gameplay/player.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -14,7 +15,7 @@ namespace Cubed { enum class Gait{ - WALK, + WALK = 0, RUN }; @@ -23,27 +24,28 @@ class World; class Player { private: using enum GameMode; - constexpr static float WALK_SPEED = 4.5f; - constexpr static float RUN_SPEED = 7.0f; - constexpr static float ACCELERATION = 10.0f; - constexpr static float DECELERATION = 15.0f; - constexpr static float G = 22.5f; + float m_max_walk_speed = DEFAULT_MAX_WALK_SPEED; + float m_max_run_speed = DEFAULT_MAX_RUN_SPEED; + float m_acceleration = DEFAULT_ACCELERATION; + float m_deceleration = DEFAULT_DECELERATION; + float m_g = DEFAULT_G; constexpr static float MAX_SPACE_ON_TIME = 0.3f; + float m_yaw = 0.0f; float m_pitch = 0.0f; float m_sensitivity = 0.15f; - float max_speed = WALK_SPEED; - float y_speed = 0.0f; + float m_max_speed = m_max_walk_speed; + float m_y_speed = 0.0f; bool can_up = true; float space_on_time = 0.0f; bool space_on = false; bool is_fly = false; - float speed = 0; + float m_xz_speed = 0.0f; glm::vec3 direction = glm::vec3(0.0f, 0.0f, 0.0f); glm::vec3 move_distance {0.0f, 0.0f, 0.0f}; @@ -91,7 +93,15 @@ public: void update_player_move_state(int key, int action); void update_scroll(double yoffset); - + float& max_walk_speed(); + float& max_run_speed(); + float& max_speed(); + float& acceleration(); + float& deceleration(); + float& g(); + + Gait& gait(); + GameMode& game_mode(); }; diff --git a/include/Cubed/gameplay/world.hpp b/include/Cubed/gameplay/world.hpp index 005d362..619725c 100644 --- a/include/Cubed/gameplay/world.hpp +++ b/include/Cubed/gameplay/world.hpp @@ -28,8 +28,6 @@ private: using ChunkUpdateList = std::vector>; using ConstChunkMap = std::unordered_map; using ChunkPosSet = std::unordered_set; - - bool m_could_gen = true; glm::vec3 m_gen_player_pos{0.0f, 0.0f, 0.0f}; std::unordered_map m_chunks; @@ -46,6 +44,8 @@ private: std::condition_variable m_gen_cv; std::atomic m_gen_running{false}; std::atomic m_need_gen_chunk{false}; + std::atomic m_is_rebuilding {false}; + std::atomic m_could_gen{true}; std::atomic m_rendering_distance{24}; std::vector m_dirty_queue; std::vector m_render_snapshots; @@ -93,6 +93,8 @@ public: void hot_reload(); + void rebuild_world(); + }; } diff --git a/include/Cubed/tools/perlin_noise.hpp b/include/Cubed/tools/perlin_noise.hpp index 871be90..426497d 100644 --- a/include/Cubed/tools/perlin_noise.hpp +++ b/include/Cubed/tools/perlin_noise.hpp @@ -9,13 +9,18 @@ class PerlinNoise { public: static void init(); static float noise(float x, float y, float z); + static void reload(); + static const unsigned& seed(); + static void seed(unsigned seed); private: static inline std::atomic is_init = false; static inline std::vector p; - + static inline unsigned m_seed = 0; + static inline bool is_seed_change = false; static float fade(float t); static float lerp(float t, float a, float b); static float grad(int hash, float x, float y, float z); + }; } \ No newline at end of file diff --git a/src/dev_panel.cpp b/src/dev_panel.cpp index 4ab2075..fa4012c 100644 --- a/src/dev_panel.cpp +++ b/src/dev_panel.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -9,6 +10,21 @@ namespace Cubed { +static constexpr const char* THEMES[] = {"Dark", "Light"}; +static constexpr const char* GAITS[] = {"Walk", "Run"}; +static constexpr const char* GAME_MODES[] = {"Creative", "Spectator"}; +static char perlin_noise_input_buffer[64]; + +static int filter_unsigned(ImGuiInputTextCallbackData* data) { + if (data->EventFlag == ImGuiInputTextFlags_CallbackCharFilter) { + char c = data->EventChar; + if (c < '0' || c > '9') { + return 1; + } + } + return 0; +} + DevPanel::DevPanel(App& app) : m_app(app) { @@ -29,6 +45,7 @@ void DevPanel::init() { if (m_theme != 1 && m_theme != 0) { m_theme = 0; } + update_player_profile(); } void DevPanel::render() { @@ -51,6 +68,8 @@ void DevPanel::render() { ImGui::Text("This is a DevPanel to control the game\n"); if (ImGui::BeginTabBar("Bar")) { show_settings_tab_item(); + show_world_tab_item(); + show_player_tab_item(); ImGui::EndTabBar(); } ImGui::End(); @@ -67,7 +86,7 @@ void DevPanel::show_settings_tab_item() { } ImGui::SameLine(); if (ImGui::Button("default##1")) { - m_config.fov = NORMAL_FOV; + m_config.fov = DEFAULT_FOV; Config::get().set("player.fov", static_cast(m_config.fov)); m_app.renderer().hot_reload(); } @@ -94,7 +113,7 @@ void DevPanel::show_settings_tab_item() { Config::get().set("window.V-Sync", m_config.v_sync); m_app.window().hot_reload(); } - constexpr const char* THEMES[] = {"Dark", "Light"}; + if (ImGui::Combo("Theme", &m_theme, THEMES, IM_ARRAYSIZE(THEMES))) { if (m_theme == 0) { ImGui::StyleColorsDark(); @@ -112,4 +131,99 @@ void DevPanel::show_settings_tab_item() { } +void DevPanel::show_world_tab_item() { + if (ImGui::BeginTabItem("world")) { + if (m_text_editing.perlin_seed) { + if (ImGui::InputText("Perlin Noise Seed", perlin_noise_input_buffer, sizeof(perlin_noise_input_buffer), + ImGuiInputTextFlags_CallbackCharFilter | + ImGuiInputTextFlags_EnterReturnsTrue, + filter_unsigned)) + { + PerlinNoise::seed(static_cast(std::strtoul(perlin_noise_input_buffer, nullptr, 10))); + m_text_editing.perlin_seed = false; + } + } + if (!m_text_editing.perlin_seed) { + ImGui::Text("Perlin Noise Seed: %u", PerlinNoise::seed()); + if (ImGui::IsItemClicked()) { + m_text_editing.perlin_seed = true; + } + } + if (ImGui::Button("Rebuild World")) { + m_app.world().rebuild_world(); + } + ImGui::EndTabItem(); + } +} + +void DevPanel::show_player_tab_item() { + if (!m_player) { + Logger::error("Player is Nullptr"); + return; + } + if (ImGui::BeginTabItem("player")) { + if (ImGui::Combo("GameMode", &m_player_profile.game_mode, GAME_MODES, IM_ARRAYSIZE(GAME_MODES))) { + if (m_player_profile.game_mode == 0) { + m_player->change_mode(GameMode::CREATIVE); + } else if (m_player_profile.game_mode == 1) { + m_player->change_mode(GameMode::SPECTATOR); + } else { + ASSERT_MSG(false, "Unknown GameMode"); + } + } + if (m_player->game_mode() == GameMode::CREATIVE) { + if (ImGui::Combo("Gait", &m_player_profile.gait, GAITS, IM_ARRAYSIZE(GAITS))) { + if (m_player_profile.gait == 0) { + m_player->gait() = Gait::WALK; + } else if (m_player_profile.gait == 1) { + m_player->gait() = Gait::RUN; + } else { + ASSERT_MSG(false, "Unknown Gait"); + } + } + } + ImGui::SliderFloat("Acceleration", &m_player->acceleration(), 1.0f, 200.0f); + ImGui::SliderFloat("Deceleration", &m_player->deceleration(), 1.0f, 200.0f); + if (m_player->game_mode() == GameMode::CREATIVE) { + m_player_profile.game_mode = 0; + ImGui::SliderFloat("MaxWalkSpeed", &m_player->max_walk_speed(), 1.0f, 200.0f); + ImGui::SliderFloat("MaxRunSpeed", &m_player->max_run_speed(), 1.0f, 500.0f); + ImGui::SliderFloat("G", &m_player->g(), 1.0f, 200.0f); + + } else if (m_player->game_mode() == GameMode::SPECTATOR) { + m_player_profile.game_mode = 1; + ImGui::SliderFloat("MaxSpeed", &m_player->max_speed(), 1.0f, 500.0f); + } + if (ImGui::Button("reset")) { + m_player->max_walk_speed() = DEFAULT_MAX_WALK_SPEED; + m_player->max_run_speed() = DEFAULT_MAX_RUN_SPEED; + m_player->acceleration() = DEFAULT_ACCELERATION; + m_player->deceleration() = DEFAULT_DECELERATION; + m_player->g() = DEFAULT_G; + m_player->change_mode(GameMode::CREATIVE); + m_player->gait() = Gait::WALK; + m_player_profile.game_mode = 0; + m_player_profile.gait = 0; + } + if (m_player->gait() == Gait::WALK) { + m_player_profile.gait = 0; + } else { + m_player_profile.gait = 1; + } + + + ImGui::EndTabItem(); + } +} + +void DevPanel::update_player_profile() { + if (!m_player) { + Logger::error("Player is Nullptr"); + ASSERT(false); + return; + } + m_player_profile.gait = std::to_underlying(m_player->gait()); + m_player_profile.game_mode = std::to_underlying(m_player->game_mode()); +} + } \ No newline at end of file diff --git a/src/gameplay/player.cpp b/src/gameplay/player.cpp index a0178ba..4b0eb8d 100644 --- a/src/gameplay/player.cpp +++ b/src/gameplay/player.cpp @@ -141,6 +141,7 @@ void Player::change_mode(GameMode mode) { } else if (mode == SPECTATOR) { is_fly = true; m_gait = Gait::RUN; + m_max_speed = m_max_run_speed; } } @@ -165,7 +166,7 @@ void Player::update(float delta_time) { m_player_pos.x, m_player_pos.y, m_player_pos.z )); - DebugCollector::get().report("speed", std::format("Speed: {:.2} m/s", speed)); + DebugCollector::get().report("speed", std::format("Speed: {:.2} m/s", m_xz_speed)); } void Player::update_player_move_state(int key, int action) { @@ -212,7 +213,7 @@ void Player::update_player_move_state(int key, int action) { if (space_on) { if (m_game_mode == CREATIVE) { is_fly = !is_fly ? true : false; - y_speed = 0.0f; + m_y_speed = 0.0f; } space_on = false; space_on_time = 0.0f; @@ -356,10 +357,10 @@ void Player::update_move(float delta_time) { } if (m_game_mode != SPECTATOR) { if (m_gait == Gait::RUN) { - max_speed = RUN_SPEED; + m_max_speed = m_max_run_speed; } if (m_gait == Gait::WALK) { - max_speed = WALK_SPEED; + m_max_speed = m_max_walk_speed; } } @@ -374,45 +375,45 @@ void Player::update_move(float delta_time) { // calculate speed if (m_move_state.forward || m_move_state.back || m_move_state.left || m_move_state.right || m_move_state.up) { direction = glm::vec3(0.0f, 0.0f, 0.0f); - speed += ACCELERATION * delta_time; - if (speed > max_speed) { - speed = max_speed; + m_xz_speed += m_acceleration * delta_time; + if (m_xz_speed > m_max_speed) { + m_xz_speed = m_max_speed; } } else { - speed += -DECELERATION * delta_time; - if (speed < 0) { - speed = 0; + m_xz_speed += -m_deceleration * delta_time; + if (m_xz_speed < 0) { + m_xz_speed = 0; direction = glm::vec3(0.0f, 0.0f, 0.0f); } } update_direction(); - move_distance = {direction.x * speed * delta_time, 0.0f, direction.z * speed * delta_time}; + move_distance = {direction.x * m_xz_speed * delta_time, 0.0f, direction.z * m_xz_speed * delta_time}; if (is_fly) { if (m_move_state.up) { - y_speed = 7.5f; + m_y_speed = 7.5f; } if (m_move_state.down) { - y_speed = -7.5f; + m_y_speed = -7.5f; } if (!m_move_state.down && !m_move_state.up) { - y_speed = 0.0f; + m_y_speed = 0.0f; } } else { if (m_move_state.up && can_up) { - y_speed = 7.5; + m_y_speed = 7.5; can_up = false; } - y_speed += -G * delta_time; + m_y_speed += -m_g * delta_time; } - move_distance.y = y_speed * delta_time; + move_distance.y = m_y_speed * delta_time; // y update_y_move(); // x @@ -482,7 +483,7 @@ void Player::update_y_move() { }; if (player_box.intersects(block_box)) { m_player_pos.y -= move_distance.y; - y_speed = 0.0f; + m_y_speed = 0.0f; if (move_distance.y < 0) { can_up = true; is_fly = false; @@ -530,14 +531,40 @@ void Player::update_z_move() { void Player::update_scroll(double yoffset) { if (m_game_mode == SPECTATOR) { if (yoffset > 0) { - max_speed += 1.0f; + if (m_max_speed < 500.0f) { + m_max_speed += 1.0f; + } } else { - if (max_speed > WALK_SPEED) { - max_speed -= 1.0f; + if (m_max_speed > 1.0f) { + m_max_speed -= 1.0f; } } } } +float& Player::max_walk_speed() { + return m_max_walk_speed; +} +float& Player::max_run_speed() { + return m_max_run_speed; +} +float& Player::max_speed() { + return m_max_speed; +} +float& Player::acceleration() { + return m_acceleration; +} +float& Player::deceleration() { + return m_deceleration; +} +float& Player::g() { + return m_g; +} +Gait& Player::gait() { + return m_gait; +} +GameMode& Player::game_mode() { + return m_game_mode; +} } diff --git a/src/gameplay/world.cpp b/src/gameplay/world.cpp index 255278b..d18058a 100644 --- a/src/gameplay/world.cpp +++ b/src/gameplay/world.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -671,4 +672,27 @@ void World::hot_reload() { need_gen(); } +void World::rebuild_world() { + if (m_is_rebuilding) { + return; + } + m_is_rebuilding = true; + stop_gen_thread(); + + { + std::scoped_lock lk(m_chunks_mutex, m_new_chunk_queue_mutex); + m_chunks.clear(); + m_new_chunk_queue.clear(); + } + m_could_gen = true; + PerlinNoise::reload(); + start_gen_thread(); + need_gen(); + + m_is_rebuilding = false; + for (auto& player : m_players) { + player.second.set_player_pos({0.0f, 255.0f, 0.0f}); + } +} + } \ No newline at end of file diff --git a/src/tools/perlin_noise.cpp b/src/tools/perlin_noise.cpp index fbb5205..2d66ff4 100644 --- a/src/tools/perlin_noise.cpp +++ b/src/tools/perlin_noise.cpp @@ -19,6 +19,7 @@ void PerlinNoise::init() { p.insert(p.end(), p.begin(), p.end()); is_init = true; + m_seed = seed; } float PerlinNoise::noise(float x, float y, float z) { @@ -73,4 +74,27 @@ float PerlinNoise::grad(int hash, float x, float y, float z) { return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); } +void PerlinNoise::reload() { + if (!is_seed_change) { + Logger::warn("Seed Not Change"); + return; + } + is_init = false; + p.resize(256); + std::iota(p.begin(), p.end(), 0); + Logger::info("Reload Perlin Noise With Seed {}", m_seed); + std::shuffle(p.begin(), p.end(), std::mt19937(m_seed)); + + p.insert(p.end(), p.begin(), p.end()); + is_init = true; + is_seed_change = false; +} + +const unsigned& PerlinNoise::seed() { + return m_seed; +} +void PerlinNoise::seed(unsigned seed) { + m_seed = seed; + is_seed_change = true; +} } \ No newline at end of file