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:
AudioSystem() = default;
~AudioSystem();
// ~AudioSystem() 在 shutdown() 中手动调用销毁
void updateVolumes();

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,13 +1,18 @@
#include <SDL2/SDL.h>
#include <algorithm>
#include <cstdio>
#include <frostbite2D/audio/audio_system.h>
#include <frostbite2D/core/application.h>
#include <frostbite2D/graphics/renderer.h>
#include <frostbite2D/graphics/camera.h>
#include <frostbite2D/graphics/renderer.h>
#include <frostbite2D/platform/switch.h>
#include <frostbite2D/types/type_math.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/types/type_math.h>
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();
}

View File

@@ -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() {}

View File

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

View File

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

View File

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

View File

@@ -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<Scene>();
SceneManager::get().PushScene(menuScene);
// auto menuScene = MakePtr<Scene>();
// 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;
}