#include "Game.h" #include "squirrel/SquirrelEx.h" #include "EngineFrame/Component/Sprite.h" #include "EngineFrame/Actor/Actor.h" #include "EngineFrame/Component/Text.h" #include "EngineFrame/Actor/Debug_Actor.h" Game::Game() { } Game::~Game() { Clear(); } void Game::Init(std::function CallBack) { // 计算帧时间 m_frameTime = 1000 / m_fps; SDL_InitSubSystem(SDL_INIT_JOYSTICK); SDL_JoystickEventState(SDL_ENABLE); SDL_JoystickOpen(0); if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not initialize! Error: %s\n", SDL_GetError()); m_isRunning = false; } m_window = SDL_CreateWindow("Game", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Screen_W, Screen_H, SDL_WINDOW_SHOWN); if (m_window == nullptr) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not Create Window! Error: %s\n", SDL_GetError()); m_isRunning = false; } // 打开所有检测到的控制器 int numControllers = SDL_NumJoysticks(); for (int i = 0; i < numControllers; i++) { if (SDL_IsGameController(i)) { SDL_GameController *controller = SDL_GameControllerOpen(i); if (controller) { SDL_Log("成功打开控制器: %s", SDL_GameControllerName(controller)); } else { SDL_Log("无法打开控制器 %d! SDL错误: %s", i, SDL_GetError()); } } } // 创建渲染器 m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_ACCELERATED); if (m_renderer == nullptr) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL could not Create Renderer! Error: %s\n", SDL_GetError()); m_isRunning = false; } // 启用渲染器的混合功能(必须,否则纹理混合模式无效) SDL_SetRenderDrawBlendMode(m_renderer, SDL_BLENDMODE_BLEND); // SDL_RenderSetScale(m_renderer, 1.2, 1.2); IMG_Init(IMG_INIT_PNG); // 初始化SDL_mixer,支持OGG格式 // 44100: 采样率, MIX_DEFAULT_FORMAT: 音频格式, 2: 声道数(立体声), 4096: 缓冲区大小 if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 4096) < 0) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "SDL_mixer初始化失败! Mix_Error: %s\n", Mix_GetError()); m_isRunning = false; } // 初始化 TTF if (TTF_Init() == -1) { SDL_LogError(SDL_LOG_CATEGORY_ERROR, "TTF 初始化失败!TTF_Error: %s\n", TTF_GetError()); m_isRunning = false; } // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); // 构造调试对象 m_DebugInfoActor = new Debug_Actor(); CallBack(); } void Game::Run() { while (m_isRunning) { u32 frameStart = SDL_GetTicks(); // 帧开始时间 SDL_Event m_event; HandleEvents(&m_event); Update(m_deltaTime); // 注意:这里使用的是上一帧的deltaTime(合理,见说明) Render(); // 帧率统计(保持不变) m_frameCount++; u32 currentTime = SDL_GetTicks(); if (currentTime - m_lastFpsPrintTime >= 1000) { u32 fps = m_frameCount; if (m_DebugInfoActor) m_DebugInfoActor->FPS = fps; m_lastFpsPrintTime = currentTime; m_frameCount = 0; } // 计算实际总帧时间(关键修改) u32 diff = SDL_GetTicks() - frameStart; // 处理耗时 if (diff < m_frameTime) { SDL_Delay(m_frameTime - diff); // 尝试延迟补全 } // 延迟后,重新计算从帧开始到现在的总时间(包含可能的延迟误差) u32 actualFrameTime = SDL_GetTicks() - frameStart; m_deltaTime = actualFrameTime / 1000.0f; // 用实际总时间更新deltaTime } } void Game::HandleEvents(SDL_Event *e) { while (SDL_PollEvent(e)) { if (e->type == SDL_QUIT) { m_isRunning = false; SDL_Log("Game Exit1"); } else if (e->type == SDL_JOYBUTTONDOWN) { if (e->jbutton.button == JOY_PLUS) { m_isRunning = false; SDL_Log("Game Exit2"); } } // 处理屏幕按下事件 else if (e->type == SDL_FINGERDOWN) { // 触发双击事件 SDL_Log("退出程序"); m_isRunning = false; SDL_Log("Game Exit3"); } if (m_scene != nullptr) m_scene->HandleEvents(e); if (m_uiScene != nullptr) m_uiScene->HandleEvents(e); } } void Game::Update(float deltaTime) { if (m_scene != nullptr) m_scene->Update(deltaTime); if (m_uiScene != nullptr) m_uiScene->Update(deltaTime); // 调试信息 if (m_DebugInfoActor != nullptr) { m_DebugInfoActor->Update(deltaTime); m_DebugInfoActor->RenderCount = RenderCount; } RenderCount = 0; } void Game::Render() { SDL_RenderClear(m_renderer); if (m_scene != nullptr) m_scene->Render(); if (m_uiScene != nullptr) m_uiScene->Render(); if (m_DebugInfoActor != nullptr) m_DebugInfoActor->Render(); SDL_RenderPresent(m_renderer); } void Game::Clear() { if (m_scene != nullptr) { m_scene->Exit(); } m_scene = nullptr; if (m_uiScene != nullptr) { m_uiScene->Exit(); } m_uiScene = nullptr; m_DebugInfoActor = nullptr; IMG_Quit(); SDL_DestroyRenderer(m_renderer); SDL_DestroyWindow(m_window); SDL_Quit(); } void Game::ChangeScene(RefPtr scene) { if (m_scene != nullptr) { m_scene->Exit(); } m_scene = scene; m_scene->Enter(); } void Game::ChangeUIScene(RefPtr scene) { if (m_uiScene != nullptr) { m_uiScene->Exit(); } m_uiScene = scene; m_uiScene->Enter(); } SDL_Renderer *Game::GetRenderer() { return m_renderer; }