diff --git a/Frostbite2D/include/frostbite2D/audio/audio_system.h b/Frostbite2D/include/frostbite2D/audio/audio_system.h index 51e327f..1f9fe02 100644 --- a/Frostbite2D/include/frostbite2D/audio/audio_system.h +++ b/Frostbite2D/include/frostbite2D/audio/audio_system.h @@ -49,7 +49,7 @@ public: private: AudioSystem() = default; - ~AudioSystem(); + // ~AudioSystem() 在 shutdown() 中手动调用销毁 void updateVolumes(); diff --git a/Frostbite2D/include/frostbite2D/graphics/renderer.h b/Frostbite2D/include/frostbite2D/graphics/renderer.h index e9e572d..a7f4751 100644 --- a/Frostbite2D/include/frostbite2D/graphics/renderer.h +++ b/Frostbite2D/include/frostbite2D/graphics/renderer.h @@ -43,7 +43,7 @@ public: private: Renderer(); - ~Renderer(); + // ~Renderer() 在 shutdown() 中手动调用销毁 void setupBlendMode(BlendMode mode); void updateUniforms(); diff --git a/Frostbite2D/include/frostbite2D/graphics/shader_manager.h b/Frostbite2D/include/frostbite2D/graphics/shader_manager.h index 20305c3..352cd05 100644 --- a/Frostbite2D/include/frostbite2D/graphics/shader_manager.h +++ b/Frostbite2D/include/frostbite2D/graphics/shader_manager.h @@ -18,11 +18,11 @@ public: Shader* getShader(const std::string& name); bool hasShader(const std::string& name) const; - - ~ShaderManager(); - + + ~ShaderManager() = default; + ShaderManager() = default; - + private: std::unordered_map> shaders_; diff --git a/Frostbite2D/include/frostbite2D/scene/scene_manager.h b/Frostbite2D/include/frostbite2D/scene/scene_manager.h index d98a704..ed8bd69 100644 --- a/Frostbite2D/include/frostbite2D/scene/scene_manager.h +++ b/Frostbite2D/include/frostbite2D/scene/scene_manager.h @@ -27,7 +27,7 @@ public: private: SceneManager() = default; - ~SceneManager(); + // ~SceneManager() 在 shutdown() 中手动调用销毁 std::vector> sceneStack_; }; diff --git a/Frostbite2D/src/frostbite2D/audio/audio_system.cpp b/Frostbite2D/src/frostbite2D/audio/audio_system.cpp index 3078587..fdf8ec0 100644 --- a/Frostbite2D/src/frostbite2D/audio/audio_system.cpp +++ b/Frostbite2D/src/frostbite2D/audio/audio_system.cpp @@ -10,9 +10,7 @@ AudioSystem& AudioSystem::get() { return instance; } -AudioSystem::~AudioSystem() { - shutdown(); -} +// 移除析构函数中的自动销毁,改为在 Application::shutdown() 中手动调用 bool AudioSystem::init(const AudioConfig& config) { if (initialized_) { diff --git a/Frostbite2D/src/frostbite2D/core/application.cpp b/Frostbite2D/src/frostbite2D/core/application.cpp index d0ed88a..09442cf 100644 --- a/Frostbite2D/src/frostbite2D/core/application.cpp +++ b/Frostbite2D/src/frostbite2D/core/application.cpp @@ -1,13 +1,18 @@ #include #include #include +#include #include -#include #include +#include #include -#include #include +#include +#include +#include #include +#include + namespace frostbite2D { Application &Application::get() { @@ -32,15 +37,6 @@ bool Application::init(const AppConfig& config) { switchInit(); #endif - // 使用SDL2创建窗口 - this->window_ = new Window(); - - // 创建窗口会使用窗口配置 - if (!window_->create(config.windowConfig)) { - SDL_Log("Failed to create window"); - return false; - } - // 初始化核心模块 if (!initCoreModules()) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize core modules"); @@ -59,16 +55,20 @@ void Application::shutdown() { running_ = false; shouldQuit_ = true; - // 关闭渲染器 - if (renderer_) { - renderer_->shutdown(); - renderer_ = nullptr; - } + // 单例销毁(反向初始化顺序) + // 场景管理 + SceneManager::get().ClearAll(); - if (window_) { - window_->destroy(); - window_ = nullptr; - } + // 渲染器(内部会清理 ShaderManager 和 Batch) + Renderer::get().shutdown(); + + // 音频系统 + AudioSystem::get().shutdown(); + + // 资源归档 + NpkArchive::get().close(); + PvfArchive::get().close(); + SoundPackArchive::get().close(); // 清理相机 if (camera_) { @@ -76,17 +76,29 @@ void Application::shutdown() { camera_ = nullptr; } + if (window_) { + window_->destroy(); + window_ = nullptr; + } + // 平台相关清理 #ifdef __SWITCH__ switchShutdown(); #endif + // 退出 SDL(添加重复调用保护) + static bool sdlQuitCalled = false; + if (!sdlQuitCalled) { + SDL_Quit(); + sdlQuitCalled = true; + } + initialized_ = false; running_ = false; } Application::~Application() { - shutdown(); + } bool Application::initCoreModules() { @@ -103,7 +115,20 @@ bool Application::initCoreModules() { #else asset.setWorkingDirectory("/switch/Frostbite2D/" + config_.appName); SDL_Log("Asset working directory: %s", asset.getWorkingDirectory().c_str()); - #endif +#endif + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { + SDL_Log("Failed to initialize SDL: %s", SDL_GetError()); + return false; + } + + // 使用SDL2创建窗口 + this->window_ = new Window(); + + // 创建窗口会使用窗口配置 + if (!window_->create(config_.windowConfig)) { + SDL_Log("Failed to create window"); + return false; + } // 初始化渲染器 renderer_ = &Renderer::get(); @@ -176,6 +201,11 @@ void Application::resume() { } void Application::mainLoop() { + // 记录程序启动时的初始时间(毫秒) + Uint32 start_time = SDL_GetTicks(); + // 定时退出时间:1秒 = 1000毫秒 + const Uint32 EXIT_DELAY = 1000; + while (!shouldQuit_) { SDL_Event event; while (SDL_PollEvent(&event)) { @@ -184,6 +214,17 @@ void Application::mainLoop() { break; } } + + // ===================== 新增:1秒定时退出 ===================== + Uint32 current_time = SDL_GetTicks(); + // 判断是否达到1秒 + if (current_time - start_time >= EXIT_DELAY) { + shouldQuit_ = true; + // 跳出事件循环 + break; + } + // ============================================================ + if (!paused_) { update(); } diff --git a/Frostbite2D/src/frostbite2D/core/window.cpp b/Frostbite2D/src/frostbite2D/core/window.cpp index 2d9bf6f..7907c9a 100644 --- a/Frostbite2D/src/frostbite2D/core/window.cpp +++ b/Frostbite2D/src/frostbite2D/core/window.cpp @@ -8,10 +8,6 @@ namespace frostbite2D { bool Window::create(const WindowConfig &cfg) { - if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { - SDL_Log("Failed to initialize SDL: %s", SDL_GetError()); - return false; - } Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN; #ifdef __SWITCH__ @@ -56,7 +52,6 @@ bool Window::create(const WindowConfig &cfg) { if (!sdlWindow_) { SDL_Log("Failed to create window: %s", SDL_GetError()); - SDL_Quit(); return false; } @@ -65,7 +60,6 @@ bool Window::create(const WindowConfig &cfg) { SDL_Log("Failed to create OpenGL context: %s", SDL_GetError()); SDL_DestroyWindow(sdlWindow_); sdlWindow_ = nullptr; - SDL_Quit(); return false; } @@ -75,7 +69,6 @@ bool Window::create(const WindowConfig &cfg) { glContext_ = nullptr; SDL_DestroyWindow(sdlWindow_); sdlWindow_ = nullptr; - SDL_Quit(); return false; } @@ -127,7 +120,6 @@ void Window::destroy() { SDL_DestroyWindow(sdlWindow_); sdlWindow_ = nullptr; } - SDL_Quit(); } void Window::poll() {} diff --git a/Frostbite2D/src/frostbite2D/graphics/renderer.cpp b/Frostbite2D/src/frostbite2D/graphics/renderer.cpp index b369768..bbbcf13 100644 --- a/Frostbite2D/src/frostbite2D/graphics/renderer.cpp +++ b/Frostbite2D/src/frostbite2D/graphics/renderer.cpp @@ -13,9 +13,7 @@ Renderer& Renderer::get() { Renderer::Renderer() = default; -Renderer::~Renderer() { - shutdown(); -} +// 移除析构函数中的自动销毁,改为在 Application::shutdown() 中手动调用 bool Renderer::init() { if (initialized_) { diff --git a/Frostbite2D/src/frostbite2D/graphics/shader_manager.cpp b/Frostbite2D/src/frostbite2D/graphics/shader_manager.cpp index cd34714..46967ab 100644 --- a/Frostbite2D/src/frostbite2D/graphics/shader_manager.cpp +++ b/Frostbite2D/src/frostbite2D/graphics/shader_manager.cpp @@ -19,9 +19,7 @@ ShaderManager& ShaderManager::get() { return instance; } -ShaderManager::~ShaderManager() { - shutdown(); -} +// 移除析构函数中的自动销毁,改为在 Application::shutdown() 中手动调用 bool ShaderManager::init(const std::string& shadersDir) { shadersDir_ = shadersDir; diff --git a/Frostbite2D/src/frostbite2D/scene/scene_manager.cpp b/Frostbite2D/src/frostbite2D/scene/scene_manager.cpp index e9ad258..eb50683 100644 --- a/Frostbite2D/src/frostbite2D/scene/scene_manager.cpp +++ b/Frostbite2D/src/frostbite2D/scene/scene_manager.cpp @@ -9,9 +9,7 @@ SceneManager& SceneManager::get() { return instance; } -SceneManager::~SceneManager() { - ClearAll(); -} +// 移除析构函数中的自动销毁,改为在 Application::shutdown() 中手动调用 void SceneManager::PushScene(Ptr scene) { if (!scene) { diff --git a/Game/src/main.cpp b/Game/src/main.cpp index 6be8e04..592befa 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -39,124 +39,124 @@ int main(int argc, char **argv) { return -1; } - SDL_Log("Starting main loop..."); + // SDL_Log("Starting main loop..."); - auto menuScene = MakePtr(); - SceneManager::get().PushScene(menuScene); + // auto menuScene = MakePtr(); + // SceneManager::get().PushScene(menuScene); - // 尝试加载精灵 - auto sprite = Sprite::createFromFile("assets/player.png"); - if (sprite) { - sprite->SetPosition(320, 300); - sprite->SetOpacity(0.8f); - // sprite->SetAnchor(Vec2(0.5f, 0.5f)); - // sprite->SetRotation(30.f); - sprite->SetZOrder(2000); - // sprite->SetScale(Vec2(-1.0f, 1.0f)); - menuScene->AddChild(sprite); - SDL_Log("Sprite created and added to scene"); - } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create sprite from file!"); - } - - // auto &archive = PvfArchive::get(); - // if (archive.open("assets/Script.pvf")) { - // archive.init(); - // // 文件内容读取 - // if (auto rawData = archive.getFileRawData("region/balmayer_north.rgn")) { - // ScriptParser parser(*rawData, "script/example.bin"); - // // // 方式1:迭代解析 - // // while (!parser.isEnd()) { - // // if (auto value = parser.next()) { - // // switch (value->type) { - // // case ScriptValueType::Integer: - // // SDL_Log("Integer: %d", value->intValue); - // // break; - // // case ScriptValueType::Float: - // // SDL_Log("Float: %f", value->floatValue); - // // break; - // // case ScriptValueType::String: - // // SDL_Log("String: %s", value->stringValue.c_str()); - // // break; - // // default: - // // break; - // // } - // // } - // // } - - // // // 方式2:批量解析 - // // parser.reset(); - // auto allValues = parser.parseAll(); - // for (const auto &value : allValues) { - // // 处理 value - // switch (value.type) { - // case ScriptValueType::Integer: - // SDL_Log("Integer: %d", value.intValue); - // break; - // case ScriptValueType::Float: - // SDL_Log("Float: %f", value.floatValue); - // break; - // case ScriptValueType::String: - // SDL_Log("String: %s", value.stringValue.c_str()); - // break; - // default: - // break; - // } - // } - // } - // } - - AudioSystem::get().init(); - AudioSystem::get().setMasterVolume(1.0f); - AudioSystem::get().setSoundVolume(0.8f); - AudioSystem::get().setMusicVolume(0.6f); - - auto bgMusic = Music::loadFromFile("assets/BackgroundMusic.mp3"); - if (bgMusic) { - bgMusic->play(); - } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load background music!"); - } - - NpkArchive &npk = NpkArchive::get(); - npk.setImagePackDirectory("assets/ImagePacks2"); - npk.setDefaultImg("sprite/interface/base.img", 0); - npk.init(); - - auto sprite1 = Sprite::createFromNpk("sprite/newtitle/nangua.img", 0); - if (sprite1) { - sprite1->SetPosition(220, 10); - // sprite1->SetScale(2.0f); - sprite->AddChild(sprite1); - } else { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create sprite from NPK!"); - } - - SoundPackArchive &archive = SoundPackArchive::get(); - archive.setSoundPackDirectory("assets/SoundPacks"); - archive.init(); - - // auto sound = Sound::loadFromNpk("sounds/ui/adventurer_maker_name.ogg"); - // if (sound) { - // sound->play(); + // // 尝试加载精灵 + // auto sprite = Sprite::createFromFile("assets/player.png"); + // if (sprite) { + // sprite->SetPosition(320, 300); + // sprite->SetOpacity(0.8f); + // // sprite->SetAnchor(Vec2(0.5f, 0.5f)); + // // sprite->SetRotation(30.f); + // sprite->SetZOrder(2000); + // // sprite->SetScale(Vec2(-1.0f, 1.0f)); + // menuScene->AddChild(sprite); + // SDL_Log("Sprite created and added to scene"); // } else { - // SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load sound!"); + // SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create sprite from file!"); // } - auto &audioDB = AudioDatabase::get(); - audioDB.loadFromFile("assets/audio.xml"); + // // auto &archive = PvfArchive::get(); + // // if (archive.open("assets/Script.pvf")) { + // // archive.init(); + // // // 文件内容读取 + // // if (auto rawData = archive.getFileRawData("region/balmayer_north.rgn")) { + // // ScriptParser parser(*rawData, "script/example.bin"); + // // // // 方式1:迭代解析 + // // // while (!parser.isEnd()) { + // // // if (auto value = parser.next()) { + // // // switch (value->type) { + // // // case ScriptValueType::Integer: + // // // SDL_Log("Integer: %d", value->intValue); + // // // break; + // // // case ScriptValueType::Float: + // // // SDL_Log("Float: %f", value->floatValue); + // // // break; + // // // case ScriptValueType::String: + // // // SDL_Log("String: %s", value->stringValue.c_str()); + // // // break; + // // // default: + // // // break; + // // // } + // // // } + // // // } - // ========== 方式 1: 最简单的 API(推荐) ========== - std::string path = audioDB.filePath("P_ICECANNON_SHOT"); - if (!path.empty()) { - SDL_Log("=== 方式 1: 直接获取文件路径 ==="); - SDL_Log("File: %s", path.c_str()); - } + // // // // 方式2:批量解析 + // // // parser.reset(); + // // auto allValues = parser.parseAll(); + // // for (const auto &value : allValues) { + // // // 处理 value + // // switch (value.type) { + // // case ScriptValueType::Integer: + // // SDL_Log("Integer: %d", value.intValue); + // // break; + // // case ScriptValueType::Float: + // // SDL_Log("Float: %f", value.floatValue); + // // break; + // // case ScriptValueType::String: + // // SDL_Log("String: %s", value.stringValue.c_str()); + // // break; + // // default: + // // break; + // // } + // // } + // // } + // // } + + // AudioSystem::get().init(); + // AudioSystem::get().setMasterVolume(1.0f); + // AudioSystem::get().setSoundVolume(0.8f); + // AudioSystem::get().setMusicVolume(0.6f); + + // auto bgMusic = Music::loadFromFile("assets/BackgroundMusic.mp3"); + // if (bgMusic) { + // bgMusic->play(); + // } else { + // SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load background music!"); + // } + + // NpkArchive &npk = NpkArchive::get(); + // npk.setImagePackDirectory("assets/ImagePacks2"); + // npk.setDefaultImg("sprite/interface/base.img", 0); + // npk.init(); + + // auto sprite1 = Sprite::createFromNpk("sprite/newtitle/nangua.img", 0); + // if (sprite1) { + // sprite1->SetPosition(220, 10); + // // sprite1->SetScale(2.0f); + // sprite->AddChild(sprite1); + // } else { + // SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create sprite from NPK!"); + // } + + // SoundPackArchive &archive = SoundPackArchive::get(); + // archive.setSoundPackDirectory("assets/SoundPacks"); + // archive.init(); + + // // auto sound = Sound::loadFromNpk("sounds/ui/adventurer_maker_name.ogg"); + // // if (sound) { + // // sound->play(); + // // } else { + // // SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load sound!"); + // // } + + // auto &audioDB = AudioDatabase::get(); + // audioDB.loadFromFile("assets/audio.xml"); + + // // ========== 方式 1: 最简单的 API(推荐) ========== + // std::string path = audioDB.filePath("P_ICECANNON_SHOT"); + // if (!path.empty()) { + // SDL_Log("=== 方式 1: 直接获取文件路径 ==="); + // SDL_Log("File: %s", path.c_str()); + // } app.run(); + SDL_Log("Application exited normally"); app.shutdown(); - SDL_Log("Application exited normally"); return 0; }