refactor(core): 重构资源销毁流程,改为集中式管理

将各模块的析构函数中自动调用shutdown()的逻辑移除,改为在Application::shutdown()中统一手动调用
调整SDL初始化和退出流程,避免重复调用
添加测试用的1秒定时退出逻辑
清理主程序中的示例代码
This commit is contained in:
2026-03-25 20:00:13 +08:00
parent 9a5b36392c
commit 0171c9d22a
11 changed files with 182 additions and 157 deletions

View File

@@ -49,7 +49,7 @@ public:
private: private:
AudioSystem() = default; AudioSystem() = default;
~AudioSystem(); // ~AudioSystem() 在 shutdown() 中手动调用销毁
void updateVolumes(); void updateVolumes();

View File

@@ -43,7 +43,7 @@ public:
private: private:
Renderer(); Renderer();
~Renderer(); // ~Renderer() 在 shutdown() 中手动调用销毁
void setupBlendMode(BlendMode mode); void setupBlendMode(BlendMode mode);
void updateUniforms(); void updateUniforms();

View File

@@ -19,7 +19,7 @@ public:
Shader* getShader(const std::string& name); Shader* getShader(const std::string& name);
bool hasShader(const std::string& name) const; bool hasShader(const std::string& name) const;
~ShaderManager(); ~ShaderManager() = default;
ShaderManager() = default; ShaderManager() = default;

View File

@@ -27,7 +27,7 @@ public:
private: private:
SceneManager() = default; SceneManager() = default;
~SceneManager(); // ~SceneManager() 在 shutdown() 中手动调用销毁
std::vector<Ptr<Scene>> sceneStack_; std::vector<Ptr<Scene>> sceneStack_;
}; };

View File

@@ -10,9 +10,7 @@ AudioSystem& AudioSystem::get() {
return instance; return instance;
} }
AudioSystem::~AudioSystem() { // 移除析构函数中的自动销毁,改为在 Application::shutdown() 中手动调用
shutdown();
}
bool AudioSystem::init(const AudioConfig& config) { bool AudioSystem::init(const AudioConfig& config) {
if (initialized_) { if (initialized_) {

View File

@@ -1,13 +1,18 @@
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <algorithm> #include <algorithm>
#include <cstdio> #include <cstdio>
#include <frostbite2D/audio/audio_system.h>
#include <frostbite2D/core/application.h> #include <frostbite2D/core/application.h>
#include <frostbite2D/graphics/renderer.h>
#include <frostbite2D/graphics/camera.h> #include <frostbite2D/graphics/camera.h>
#include <frostbite2D/graphics/renderer.h>
#include <frostbite2D/platform/switch.h> #include <frostbite2D/platform/switch.h>
#include <frostbite2D/types/type_math.h>
#include <frostbite2D/resource/asset.h> #include <frostbite2D/resource/asset.h>
#include <frostbite2D/resource/npk_archive.h>
#include <frostbite2D/resource/pvf_archive.h>
#include <frostbite2D/resource/sound_pack_archive.h>
#include <frostbite2D/scene/scene_manager.h> #include <frostbite2D/scene/scene_manager.h>
#include <frostbite2D/types/type_math.h>
namespace frostbite2D { namespace frostbite2D {
Application &Application::get() { Application &Application::get() {
@@ -32,15 +37,6 @@ bool Application::init(const AppConfig& config) {
switchInit(); switchInit();
#endif #endif
// 使用SDL2创建窗口
this->window_ = new Window();
// 创建窗口会使用窗口配置
if (!window_->create(config.windowConfig)) {
SDL_Log("Failed to create window");
return false;
}
// 初始化核心模块 // 初始化核心模块
if (!initCoreModules()) { if (!initCoreModules()) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize core modules"); SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize core modules");
@@ -59,16 +55,20 @@ void Application::shutdown() {
running_ = false; running_ = false;
shouldQuit_ = true; shouldQuit_ = true;
// 关闭渲染器 // 单例销毁(反向初始化顺序)
if (renderer_) { // 场景管理
renderer_->shutdown(); SceneManager::get().ClearAll();
renderer_ = nullptr;
}
if (window_) { // 渲染器(内部会清理 ShaderManager 和 Batch
window_->destroy(); Renderer::get().shutdown();
window_ = nullptr;
} // 音频系统
AudioSystem::get().shutdown();
// 资源归档
NpkArchive::get().close();
PvfArchive::get().close();
SoundPackArchive::get().close();
// 清理相机 // 清理相机
if (camera_) { if (camera_) {
@@ -76,17 +76,29 @@ void Application::shutdown() {
camera_ = nullptr; camera_ = nullptr;
} }
if (window_) {
window_->destroy();
window_ = nullptr;
}
// 平台相关清理 // 平台相关清理
#ifdef __SWITCH__ #ifdef __SWITCH__
switchShutdown(); switchShutdown();
#endif #endif
// 退出 SDL添加重复调用保护
static bool sdlQuitCalled = false;
if (!sdlQuitCalled) {
SDL_Quit();
sdlQuitCalled = true;
}
initialized_ = false; initialized_ = false;
running_ = false; running_ = false;
} }
Application::~Application() { Application::~Application() {
shutdown();
} }
bool Application::initCoreModules() { bool Application::initCoreModules() {
@@ -103,7 +115,20 @@ bool Application::initCoreModules() {
#else #else
asset.setWorkingDirectory("/switch/Frostbite2D/" + config_.appName); asset.setWorkingDirectory("/switch/Frostbite2D/" + config_.appName);
SDL_Log("Asset working directory: %s", asset.getWorkingDirectory().c_str()); 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(); renderer_ = &Renderer::get();
@@ -176,6 +201,11 @@ void Application::resume() {
} }
void Application::mainLoop() { void Application::mainLoop() {
// 记录程序启动时的初始时间(毫秒)
Uint32 start_time = SDL_GetTicks();
// 定时退出时间1秒 = 1000毫秒
const Uint32 EXIT_DELAY = 1000;
while (!shouldQuit_) { while (!shouldQuit_) {
SDL_Event event; SDL_Event event;
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
@@ -184,6 +214,17 @@ void Application::mainLoop() {
break; break;
} }
} }
// ===================== 新增1秒定时退出 =====================
Uint32 current_time = SDL_GetTicks();
// 判断是否达到1秒
if (current_time - start_time >= EXIT_DELAY) {
shouldQuit_ = true;
// 跳出事件循环
break;
}
// ============================================================
if (!paused_) { if (!paused_) {
update(); update();
} }

View File

@@ -8,10 +8,6 @@
namespace frostbite2D { namespace frostbite2D {
bool Window::create(const WindowConfig &cfg) { 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; Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN;
#ifdef __SWITCH__ #ifdef __SWITCH__
@@ -56,7 +52,6 @@ bool Window::create(const WindowConfig &cfg) {
if (!sdlWindow_) { if (!sdlWindow_) {
SDL_Log("Failed to create window: %s", SDL_GetError()); SDL_Log("Failed to create window: %s", SDL_GetError());
SDL_Quit();
return false; return false;
} }
@@ -65,7 +60,6 @@ bool Window::create(const WindowConfig &cfg) {
SDL_Log("Failed to create OpenGL context: %s", SDL_GetError()); SDL_Log("Failed to create OpenGL context: %s", SDL_GetError());
SDL_DestroyWindow(sdlWindow_); SDL_DestroyWindow(sdlWindow_);
sdlWindow_ = nullptr; sdlWindow_ = nullptr;
SDL_Quit();
return false; return false;
} }
@@ -75,7 +69,6 @@ bool Window::create(const WindowConfig &cfg) {
glContext_ = nullptr; glContext_ = nullptr;
SDL_DestroyWindow(sdlWindow_); SDL_DestroyWindow(sdlWindow_);
sdlWindow_ = nullptr; sdlWindow_ = nullptr;
SDL_Quit();
return false; return false;
} }
@@ -127,7 +120,6 @@ void Window::destroy() {
SDL_DestroyWindow(sdlWindow_); SDL_DestroyWindow(sdlWindow_);
sdlWindow_ = nullptr; sdlWindow_ = nullptr;
} }
SDL_Quit();
} }
void Window::poll() {} void Window::poll() {}

View File

@@ -13,9 +13,7 @@ Renderer& Renderer::get() {
Renderer::Renderer() = default; Renderer::Renderer() = default;
Renderer::~Renderer() { // 移除析构函数中的自动销毁,改为在 Application::shutdown() 中手动调用
shutdown();
}
bool Renderer::init() { bool Renderer::init() {
if (initialized_) { if (initialized_) {

View File

@@ -19,9 +19,7 @@ ShaderManager& ShaderManager::get() {
return instance; return instance;
} }
ShaderManager::~ShaderManager() { // 移除析构函数中的自动销毁,改为在 Application::shutdown() 中手动调用
shutdown();
}
bool ShaderManager::init(const std::string& shadersDir) { bool ShaderManager::init(const std::string& shadersDir) {
shadersDir_ = shadersDir; shadersDir_ = shadersDir;

View File

@@ -9,9 +9,7 @@ SceneManager& SceneManager::get() {
return instance; return instance;
} }
SceneManager::~SceneManager() { // 移除析构函数中的自动销毁,改为在 Application::shutdown() 中手动调用
ClearAll();
}
void SceneManager::PushScene(Ptr<Scene> scene) { void SceneManager::PushScene(Ptr<Scene> scene) {
if (!scene) { if (!scene) {

View File

@@ -39,124 +39,124 @@ int main(int argc, char **argv) {
return -1; return -1;
} }
SDL_Log("Starting main loop..."); // SDL_Log("Starting main loop...");
auto menuScene = MakePtr<Scene>(); // auto menuScene = MakePtr<Scene>();
SceneManager::get().PushScene(menuScene); // SceneManager::get().PushScene(menuScene);
// 尝试加载精灵 // // 尝试加载精灵
auto sprite = Sprite::createFromFile("assets/player.png"); // auto sprite = Sprite::createFromFile("assets/player.png");
if (sprite) { // if (sprite) {
sprite->SetPosition(320, 300); // sprite->SetPosition(320, 300);
sprite->SetOpacity(0.8f); // sprite->SetOpacity(0.8f);
// sprite->SetAnchor(Vec2(0.5f, 0.5f)); // // sprite->SetAnchor(Vec2(0.5f, 0.5f));
// sprite->SetRotation(30.f); // // sprite->SetRotation(30.f);
sprite->SetZOrder(2000); // sprite->SetZOrder(2000);
// sprite->SetScale(Vec2(-1.0f, 1.0f)); // // sprite->SetScale(Vec2(-1.0f, 1.0f));
menuScene->AddChild(sprite); // menuScene->AddChild(sprite);
SDL_Log("Sprite created and added to scene"); // SDL_Log("Sprite created and added to scene");
} else { // } else {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create sprite from file!"); // SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create sprite from file!");
} // }
// auto &archive = PvfArchive::get(); // // auto &archive = PvfArchive::get();
// if (archive.open("assets/Script.pvf")) { // // if (archive.open("assets/Script.pvf")) {
// archive.init(); // // archive.init();
// // 文件内容读取 // // // 文件内容读取
// if (auto rawData = archive.getFileRawData("region/balmayer_north.rgn")) { // // if (auto rawData = archive.getFileRawData("region/balmayer_north.rgn")) {
// ScriptParser parser(*rawData, "script/example.bin"); // // ScriptParser parser(*rawData, "script/example.bin");
// // // 方式1迭代解析 // // // // 方式1迭代解析
// // while (!parser.isEnd()) { // // // while (!parser.isEnd()) {
// // if (auto value = parser.next()) { // // // if (auto value = parser.next()) {
// // switch (value->type) { // // // 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: // // case ScriptValueType::Integer:
// // SDL_Log("Integer: %d", value->intValue); // // SDL_Log("Integer: %d", value.intValue);
// // break; // // break;
// // case ScriptValueType::Float: // // case ScriptValueType::Float:
// // SDL_Log("Float: %f", value->floatValue); // // SDL_Log("Float: %f", value.floatValue);
// // break; // // break;
// // case ScriptValueType::String: // // case ScriptValueType::String:
// // SDL_Log("String: %s", value->stringValue.c_str()); // // SDL_Log("String: %s", value.stringValue.c_str());
// // break; // // break;
// // default: // // default:
// // break; // // break;
// // } // // }
// // } // // }
// // } // // }
// // }
// // // 方式2批量解析 // AudioSystem::get().init();
// // parser.reset(); // AudioSystem::get().setMasterVolume(1.0f);
// auto allValues = parser.parseAll(); // AudioSystem::get().setSoundVolume(0.8f);
// for (const auto &value : allValues) { // AudioSystem::get().setMusicVolume(0.6f);
// // 处理 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(); // auto bgMusic = Music::loadFromFile("assets/BackgroundMusic.mp3");
AudioSystem::get().setMasterVolume(1.0f); // if (bgMusic) {
AudioSystem::get().setSoundVolume(0.8f); // bgMusic->play();
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 { // } else {
// SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load sound!"); // SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to load background music!");
// } // }
auto &audioDB = AudioDatabase::get(); // NpkArchive &npk = NpkArchive::get();
audioDB.loadFromFile("assets/audio.xml"); // npk.setImagePackDirectory("assets/ImagePacks2");
// npk.setDefaultImg("sprite/interface/base.img", 0);
// npk.init();
// ========== 方式 1: 最简单的 API推荐 ========== // auto sprite1 = Sprite::createFromNpk("sprite/newtitle/nangua.img", 0);
std::string path = audioDB.filePath("P_ICECANNON_SHOT"); // if (sprite1) {
if (!path.empty()) { // sprite1->SetPosition(220, 10);
SDL_Log("=== 方式 1: 直接获取文件路径 ==="); // // sprite1->SetScale(2.0f);
SDL_Log("File: %s", path.c_str()); // 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(); app.run();
SDL_Log("Application exited normally");
app.shutdown(); app.shutdown();
SDL_Log("Application exited normally");
return 0; return 0;
} }