From 03f539eb9fe44e49eb02e300521d2bc23788ab23 Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Tue, 14 Jul 2026 11:27:39 +0800 Subject: [PATCH] feat(scene): implement pause menu with UI manager and escape key toggling Add PauseMenuUIManager class and integrate pause state into WorldScene. Escape key toggles pause in ClientPlayer and PauseMenuUIManager. Refactor Window mouse and imgui control to support pause state. --- include/Cubed/scene/world_scene.hpp | 5 ++ include/Cubed/ui/image.hpp | 4 + include/Cubed/ui/pasue_menu_ui_manager.hpp | 20 +++++ include/Cubed/window.hpp | 9 ++- src/CMakeLists.txt | 1 + src/app.cpp | 22 +++--- src/gameplay/client_player.cpp | 7 ++ src/scene/world_scene.cpp | 85 ++++++++++++++-------- src/ui/button.cpp | 2 - src/ui/pause_menu_ui_manager.cpp | 41 +++++++++++ src/window.cpp | 65 +++++++++-------- 11 files changed, 187 insertions(+), 74 deletions(-) create mode 100644 include/Cubed/ui/pasue_menu_ui_manager.hpp create mode 100644 src/ui/pause_menu_ui_manager.cpp diff --git a/include/Cubed/scene/world_scene.hpp b/include/Cubed/scene/world_scene.hpp index 376f14c..e1cba13 100644 --- a/include/Cubed/scene/world_scene.hpp +++ b/include/Cubed/scene/world_scene.hpp @@ -5,6 +5,7 @@ #include "Cubed/gameplay/client_world.hpp" #include "Cubed/gameplay/network_server.hpp" #include "Cubed/scene/scene.hpp" +#include "Cubed/ui/pasue_menu_ui_manager.hpp" #include "Cubed/ui/world_ui_manager.hpp" namespace Cubed { class SceneManager; @@ -28,6 +29,8 @@ public: SceneManager& scene_manager(); ClientWorld& client_world(); ServerWorld& server_world(); + bool pause() const; + void set_pause(bool pause); private: SceneManager& m_scene_manager; @@ -36,6 +39,8 @@ private: NetworkServer m_server; std::shared_ptr m_client; ClientWorld m_client_world; + bool m_paused = false; + PauseMenuUIManager m_pasue_menu; WorldUIManager m_ui_manager; const Argument& m_argument; }; diff --git a/include/Cubed/ui/image.hpp b/include/Cubed/ui/image.hpp index 06495cb..dd42a54 100644 --- a/include/Cubed/ui/image.hpp +++ b/include/Cubed/ui/image.hpp @@ -8,6 +8,10 @@ namespace Cubed { class TextureManager; class Image : public Widget { public: + Image(const Image&) = delete; + Image(Image&&) = delete; + Image& operator=(const Image&) = delete; + Image& operator=(Image&&) = delete; Image(Widget* parent); Image& set_image(const std::string& path, TextureManager& texture_manager); diff --git a/include/Cubed/ui/pasue_menu_ui_manager.hpp b/include/Cubed/ui/pasue_menu_ui_manager.hpp new file mode 100644 index 0000000..5de08be --- /dev/null +++ b/include/Cubed/ui/pasue_menu_ui_manager.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "Cubed/ui/ui_manager.hpp" +namespace Cubed { +class WorldScene; +class PauseMenuUIManager : public UIManager { +public: + PauseMenuUIManager(const PauseMenuUIManager&) = delete; + PauseMenuUIManager(PauseMenuUIManager&&) = delete; + PauseMenuUIManager& operator=(const PauseMenuUIManager&) = delete; + PauseMenuUIManager& operator=(PauseMenuUIManager&&) = delete; + PauseMenuUIManager(WorldScene& scene); + void init() override; + +private: + WorldScene& m_scene; + + bool handle_key_event(const KeyEvent& e) override; +}; +} // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/window.hpp b/include/Cubed/window.hpp index ee21f84..6772f27 100644 --- a/include/Cubed/window.hpp +++ b/include/Cubed/window.hpp @@ -25,7 +25,9 @@ public: void hot_reload(); void toggle_fullscreen(); - void toggle_mouse_able(); + + void enable_mouse(); + void disable_mouse(); void set_camera(Camera* camera); Camera* camera(); @@ -34,6 +36,10 @@ public: void should_close_window(); + bool is_enable_imgui() const; + + void set_imgui_enabled(bool enable); + private: bool m_mouse_enable = false; bool m_imgui_init = false; @@ -43,6 +49,7 @@ private: int m_window_height; Config& m_config; Camera* m_camera = nullptr; + bool m_imgui_enable = false; bool handle_key_event(const KeyEvent& e); bool handle_window_resize_event(const WindowResizeEvent& e); bool handle_mouse_button_event(const MouseButtonEvent& e); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4afa922..a78121b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -70,4 +70,5 @@ target_sources(${PROJECT_NAME} ui/column_layout.cpp ui/rect.cpp ui/ui_manager.cpp + ui/pause_menu_ui_manager.cpp ) \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp index 26cb977..ac830f5 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -28,14 +28,13 @@ void App::cursor_position_callback(GLFWwindow* window, double xpos, App* app = static_cast(glfwGetWindowUserPointer(window)); ASSERT_MSG(app, "nullptr"); - if (io.WantCaptureMouse && app->m_window.is_mouse_enable()) { + if (io.WantCaptureMouse && app->m_window.is_enable_imgui()) { ImGui_ImplGlfw_CursorPosCallback(window, xpos, ypos); return; } - if (!app->m_window.is_mouse_enable()) { - app->m_scene_manager.handle_event( - MouseMoveEvent{static_cast(xpos), static_cast(ypos)}); - } + + app->m_scene_manager.handle_event( + MouseMoveEvent{static_cast(xpos), static_cast(ypos)}); } void App::init(int argc, char** argv) { handle_toml(); @@ -173,7 +172,7 @@ void App::key_callback(GLFWwindow* window, int key, int scancode, int action, ASSERT_MSG(app, "nullptr"); // ImGui_ImplGlfw_CursorEnterCallback(window, // !app->m_window.is_mouse_enable()); - if (io.WantCaptureKeyboard && app->m_window.is_mouse_enable()) { + if (io.WantCaptureKeyboard && app->m_window.is_enable_imgui()) { if ((key == GLFW_KEY_LEFT_ALT) && action == GLFW_PRESS) { app->dispatch_event(KeyEvent{Key::LEFT_ALT, KeyAction::PRESS}); return; @@ -532,7 +531,7 @@ void App::mouse_button_callback(GLFWwindow* window, int button, int action, ImGuiIO& io = ImGui::GetIO(); App* app = static_cast(glfwGetWindowUserPointer(window)); ASSERT_MSG(app, "nullptr"); - if (io.WantCaptureMouse && app->m_window.is_mouse_enable()) { + if (io.WantCaptureMouse && app->m_window.is_enable_imgui()) { ImGui_ImplGlfw_MouseButtonCallback(window, button, action, mods); return; } @@ -582,7 +581,7 @@ void App::window_focus_callback(GLFWwindow* window, int focused) { ImGuiIO& io = ImGui::GetIO(); App* app = static_cast(glfwGetWindowUserPointer(window)); ASSERT_MSG(app, "nullptr"); - if (io.WantCaptureMouse && app->m_window.is_mouse_enable()) { + if (io.WantCaptureMouse && app->m_window.is_enable_imgui()) { ImGui_ImplGlfw_WindowFocusCallback(window, focused); return; } @@ -616,7 +615,7 @@ void App::mouse_scroll_callback(GLFWwindow* window, double xoffset, App* app = static_cast(glfwGetWindowUserPointer(window)); ASSERT_MSG(app, "nullptr"); - if (io.WantCaptureMouse && app->m_window.is_mouse_enable()) { + if (io.WantCaptureMouse && app->m_window.is_enable_imgui()) { ImGui_ImplGlfw_ScrollCallback(window, xoffset, yoffset); return; } @@ -627,7 +626,7 @@ void App::cursor_enter_callback(GLFWwindow* window, int entered) { ImGuiIO& io = ImGui::GetIO(); App* app = static_cast(glfwGetWindowUserPointer(window)); ASSERT_MSG(app, "nullptr"); - if (io.WantCaptureMouse && app->m_window.is_mouse_enable()) { + if (io.WantCaptureMouse && app->m_window.is_enable_imgui()) { ImGui_ImplGlfw_CursorEnterCallback(window, entered); return; } @@ -637,8 +636,9 @@ void App::char_callback(GLFWwindow* window, unsigned int c) { ImGuiIO& io = ImGui::GetIO(); App* app = static_cast(glfwGetWindowUserPointer(window)); ASSERT_MSG(app, "nullptr"); - if (io.WantCaptureKeyboard && app->m_window.is_mouse_enable()) { + if (io.WantCaptureKeyboard && app->m_window.is_enable_imgui()) { ImGui_ImplGlfw_CharCallback(window, c); + return; } } diff --git a/src/gameplay/client_player.cpp b/src/gameplay/client_player.cpp index 82c1c96..0df5659 100644 --- a/src/gameplay/client_player.cpp +++ b/src/gameplay/client_player.cpp @@ -4,6 +4,7 @@ #include "Cubed/config.hpp" #include "Cubed/debug_collector.hpp" #include "Cubed/gameplay/client_world.hpp" +#include "Cubed/scene/world_scene.hpp" namespace {} // namespace @@ -582,6 +583,12 @@ bool ClientPlayer::handle_mouse_button_event(const MouseButtonEvent& e) { } bool ClientPlayer::handle_key_event(const KeyEvent& e) { + + if (e.key == Key::ESCAPE && e.action == KeyAction::PRESS) { + m_world.world_scene().set_pause(true); + return true; + } + if (update_player_move_state(e.key, e.action)) { return true; } diff --git a/src/scene/world_scene.cpp b/src/scene/world_scene.cpp index 94a37b3..3b825e2 100644 --- a/src/scene/world_scene.cpp +++ b/src/scene/world_scene.cpp @@ -8,7 +8,8 @@ WorldScene::WorldScene(SceneManager& scene_manager) : m_scene_manager(scene_manager), m_dev_panel(*this), m_client_world(scene_manager.app().audio(), scene_manager.app().config(), *this), - m_ui_manager(*this), m_argument(scene_manager.app().argument()) {} + m_pasue_menu(*this), m_ui_manager(*this), + m_argument(scene_manager.app().argument()) {} WorldScene::~WorldScene() { if (m_client) { @@ -17,45 +18,61 @@ WorldScene::~WorldScene() { } void WorldScene::update(float dt) { - m_client_world.update(dt); - m_camera.update_move_camera(); - m_client_world.get_audio().update_listener(m_camera.get_camera_pos(), - m_camera.get_camera_front(), - glm::vec3(0, 1, 0)); + if (m_paused) { + m_pasue_menu.update(dt); + } else { + m_client_world.update(dt); + m_camera.update_move_camera(); + m_client_world.get_audio().update_listener(m_camera.get_camera_pos(), + m_camera.get_camera_front(), + glm::vec3(0, 1, 0)); - /* - const auto& player = m_client_world.get_player(); - if (player_gait != player.get_gait()) { - player_gait = player.get_gait(); - float fov = m_client_world.get("player.fov", 70.0f); - if (player_gait == Gait::WALK) { - m_renderer.update_fov(fov); - } - if (player_gait == Gait::RUN) { - m_renderer.update_fov(fov + 5.0f); - } - }*/ - m_ui_manager.update(dt); + /* + const auto& player = m_client_world.get_player(); + if (player_gait != player.get_gait()) { + player_gait = player.get_gait(); + float fov = m_client_world.get("player.fov", 70.0f); + if (player_gait == Gait::WALK) { + m_renderer.update_fov(fov); + } + if (player_gait == Gait::RUN) { + m_renderer.update_fov(fov + 5.0f); + } + }*/ + m_ui_manager.update(dt); + } } void WorldScene::render(Renderer& renderer) { renderer.render_world(m_client_world); - renderer.render_dev_panel(m_dev_panel); - m_ui_manager.render(renderer); + + if (m_paused) { + m_pasue_menu.render(renderer); + } else { + renderer.render_dev_panel(m_dev_panel); + } } bool WorldScene::handle_event(const Event& e) { - if (m_ui_manager.handle_event(e)) { - return true; - } - if (m_camera.handle_event(e)) { - return true; - } - // world event needs to be processed last - if (m_client_world.handle_event(e)) { - return true; + if (m_paused) { + + if (m_pasue_menu.handle_event(e)) { + + return true; + } + } else { + if (m_ui_manager.handle_event(e)) { + return true; + } + if (m_camera.handle_event(e)) { + return true; + } + // world event needs to be processed last + if (m_client_world.handle_event(e)) { + return true; + } } return false; } @@ -76,6 +93,7 @@ void WorldScene::on_enter() { m_camera.camera_init(&m_client_world.get_player()); m_scene_manager.app().window().set_camera(&m_camera); m_dev_panel.init(); + m_pasue_menu.init(); m_ui_manager.init(); m_scene_manager.app().window().set_game_running(true); @@ -95,4 +113,11 @@ Camera& WorldScene::camera() { return m_camera; } SceneManager& WorldScene::scene_manager() { return m_scene_manager; } ClientWorld& WorldScene::client_world() { return m_client_world; } ServerWorld& WorldScene::server_world() { return m_server.server_world(); } +bool WorldScene::pause() const { return m_paused; } +void WorldScene::set_pause(bool pause) { + m_paused = pause; + auto& window = m_scene_manager.app().window(); + Logger::info("pause {}", m_paused); + window.set_game_running(!m_paused); +} } // namespace Cubed \ No newline at end of file diff --git a/src/ui/button.cpp b/src/ui/button.cpp index ecae590..ee8c537 100644 --- a/src/ui/button.cpp +++ b/src/ui/button.cpp @@ -23,11 +23,9 @@ void Button::on_render(Renderer& renderer) { bool Button::handle_mouse_move_event(const MouseMoveEvent& e) { auto pos = m_background->pos(); - if (e.xpos >= pos.x && e.xpos <= pos.x + width() && e.ypos >= pos.y && e.ypos <= pos.y + height()) { m_hovered = true; - return true; } m_hovered = false; diff --git a/src/ui/pause_menu_ui_manager.cpp b/src/ui/pause_menu_ui_manager.cpp new file mode 100644 index 0000000..b4ebb52 --- /dev/null +++ b/src/ui/pause_menu_ui_manager.cpp @@ -0,0 +1,41 @@ +#include "Cubed/app.hpp" +#include "Cubed/render/renderer.hpp" +#include "Cubed/scene/scene_manager.hpp" +#include "Cubed/scene/world_scene.hpp" +#include "Cubed/ui/button.hpp" +#include "Cubed/ui/pasue_menu_ui_manager.hpp" +#include "Cubed/ui/rect.hpp" +namespace Cubed { +PauseMenuUIManager::PauseMenuUIManager(WorldScene& scene) : m_scene(scene) {} +void PauseMenuUIManager::init() { + auto rect = std::make_unique(nullptr); + + rect->set_fill(true); + rect->set_color(Color::BLACK); + rect->set_alpha(0.5f); + rect->set_anchor(Anchor::TOP_LEFT); + auto& renderer = m_scene.scene_manager().app().renderer(); + rect->set_window_size(renderer.window_width(), renderer.window_height()); + auto& back_main = rect->add_child