diff --git a/core/Base/Game.cpp b/core/Base/Game.cpp index 1c093f53..03dcc620 100644 --- a/core/Base/Game.cpp +++ b/core/Base/Game.cpp @@ -42,20 +42,7 @@ void e2d::Game::destroyInstance() void e2d::Game::start() { - auto gc = GC::getInstance(); - auto input = Input::getInstance(); - auto window = Window::getInstance(); - auto renderer = Renderer::getInstance(); - auto timer = Timer::getInstance(); - auto sceneManager = SceneManager::getInstance(); - auto actionManager = ActionManager::getInstance(); - - if (!input || !window || !renderer || !timer || !sceneManager || !actionManager) - { - throw SystemException(L"初始化失败"); - } - - HWND hWnd = window->getHWnd(); + HWND hWnd = Window::getInstance()->getHWnd(); if (hWnd == nullptr) { throw SystemException(L"无法创建窗口"); @@ -64,7 +51,7 @@ void e2d::Game::start() // 显示窗口 ::ShowWindow(hWnd, SW_SHOWNORMAL); ::UpdateWindow(hWnd); - window->poll(); + Window::getInstance()->poll(); // 开始游戏 Duration interval; @@ -76,31 +63,43 @@ void e2d::Game::start() while (!_quit) { _now = Time::now(); - interval = _now - _last; - if (_frameInterval < interval) + if (_config.isVSyncEnabled()) { - _last = _now; - - input->update(); - timer->update(); - actionManager->update(); - sceneManager->update(); - renderer->render(); - window->poll(); - gc->flush(); + __update(); } else { - wait = (_frameInterval - interval).milliseconds() - 1; - if (wait > 1) + interval = _now - _last; + + if (_frameInterval < interval) { - std::this_thread::sleep_for(milliseconds(wait)); + _last = _now; + __update(); + } + else + { + wait = (_frameInterval - interval).milliseconds() - 1; + if (wait > 1) + { + std::this_thread::sleep_for(milliseconds(wait)); + } } } } } +void e2d::Game::__update() +{ + Input::getInstance()->update(); + Timer::getInstance()->update(); + ActionManager::getInstance()->update(); + SceneManager::getInstance()->update(); + Renderer::getInstance()->render(); + Window::getInstance()->poll(); + GC::getInstance()->flush(); +} + void e2d::Game::pause() { _paused = true; @@ -124,18 +123,25 @@ bool e2d::Game::isPaused() void e2d::Game::setConfig(const Config& config) { - _config = config; - - if (_config.isSoundEnabled()) + if (_config.isSoundEnabled() != config.isSoundEnabled()) { - Player::getInstance()->getXAudio2()->StartEngine(); - } - else - { - Player::getInstance()->getXAudio2()->StopEngine(); + if (config.isSoundEnabled()) + Player::getInstance()->getXAudio2()->StartEngine(); + else + Player::getInstance()->getXAudio2()->StopEngine(); } - _frameInterval = Duration(_config.getFrameInterval()); + if (_config.getFrameInterval() != config.getFrameInterval()) + { + _frameInterval = Duration(config.getFrameInterval()); + } + + if (_config.isVSyncEnabled() != config.isVSyncEnabled()) + { + Renderer::getInstance()->discardDeviceResources(); + } + + _config = config; } const e2d::Config& e2d::Game::getConfig() diff --git a/core/Base/Renderer.cpp b/core/Base/Renderer.cpp index 519b3831..7973e183 100644 --- a/core/Base/Renderer.cpp +++ b/core/Base/Renderer.cpp @@ -45,8 +45,6 @@ e2d::Renderer::Renderer() , _clearColor(D2D1::ColorF(D2D1::ColorF::Black)) { CoInitialize(nullptr); - - this->__createDeviceResources(); } e2d::Renderer::~Renderer() @@ -59,53 +57,7 @@ e2d::Renderer::~Renderer() CoUninitialize(); } -bool e2d::Renderer::__createDeviceResources() -{ - HRESULT hr = S_OK; - - if (!_renderTarget) - { - HWND hWnd = Window::getInstance()->getHWnd(); - - // 创建设备相关资源。这些资源应在 Direct3D 设备消失时重建 - RECT rc; - GetClientRect(hWnd, &rc); - - D2D1_SIZE_U size = D2D1::SizeU( - rc.right - rc.left, - rc.bottom - rc.top - ); - - // 创建一个 Direct2D 渲染目标 - hr = Renderer::getFactory()->CreateHwndRenderTarget( - D2D1::RenderTargetProperties(), - D2D1::HwndRenderTargetProperties(hWnd, size, D2D1_PRESENT_OPTIONS_IMMEDIATELY), - &_renderTarget - ); - - if (FAILED(hr)) - { - throw SystemException(L"Create ID2D1HwndRenderTarget failed"); - } - else - { - // 创建画刷 - hr = _renderTarget->CreateSolidColorBrush( - D2D1::ColorF(D2D1::ColorF::White), - &_solidBrush - ); - } - - if (FAILED(hr)) - { - throw SystemException(L"Create ID2D1SolidColorBrush failed"); - } - } - - return SUCCEEDED(hr); -} - -void e2d::Renderer::__discardDeviceResources() +void e2d::Renderer::discardDeviceResources() { SafeRelease(_renderTarget); SafeRelease(_solidBrush); @@ -117,12 +69,12 @@ void e2d::Renderer::render() HRESULT hr = S_OK; // 创建设备相关资源 - Renderer::__createDeviceResources(); + auto renderTarget = this->getRenderTarget(); // 开始渲染 - _renderTarget->BeginDraw(); + renderTarget->BeginDraw(); // 使用背景色清空屏幕 - _renderTarget->Clear(_clearColor); + renderTarget->Clear(_clearColor); // 渲染场景 SceneManager::getInstance()->render(); @@ -134,14 +86,14 @@ void e2d::Renderer::render() } // 终止渲染 - hr = _renderTarget->EndDraw(); + hr = renderTarget->EndDraw(); if (hr == D2DERR_RECREATE_TARGET) { // 如果 Direct3D 设备在执行过程中消失,将丢弃当前的设备相关资源 // 并在下一次调用时重建资源 hr = S_OK; - this->__discardDeviceResources(); + this->discardDeviceResources(); } if (FAILED(hr)) @@ -225,11 +177,54 @@ void e2d::Renderer::setBackgroundColor(Color color) ID2D1HwndRenderTarget * e2d::Renderer::getRenderTarget() { + if (!_renderTarget) + { + HWND hWnd = Window::getInstance()->getHWnd(); + + // 创建设备相关资源。这些资源应在 Direct3D 设备消失时重建 + RECT rc; + GetClientRect(hWnd, &rc); + + D2D1_SIZE_U size = D2D1::SizeU( + rc.right - rc.left, + rc.bottom - rc.top + ); + + bool VSyncEnabled = Game::getInstance()->getConfig().isVSyncEnabled(); + + // 创建一个 Direct2D 渲染目标 + HRESULT hr = Renderer::getFactory()->CreateHwndRenderTarget( + D2D1::RenderTargetProperties(), + D2D1::HwndRenderTargetProperties( + hWnd, + size, + VSyncEnabled ? D2D1_PRESENT_OPTIONS_NONE : D2D1_PRESENT_OPTIONS_IMMEDIATELY), + &_renderTarget + ); + + if (FAILED(hr)) + { + throw SystemException(L"Create ID2D1HwndRenderTarget failed"); + } + } return _renderTarget; } ID2D1SolidColorBrush * e2d::Renderer::getSolidColorBrush() { + if (!_solidBrush) + { + // 创建画刷 + HRESULT hr = this->getRenderTarget()->CreateSolidColorBrush( + D2D1::ColorF(D2D1::ColorF::White), + &_solidBrush + ); + + if (FAILED(hr)) + { + throw SystemException(L"Create ID2D1SolidColorBrush failed"); + } + } return _solidBrush; } diff --git a/core/Common/Config.cpp b/core/Common/Config.cpp index 8a2c9db5..c4ca9314 100644 --- a/core/Common/Config.cpp +++ b/core/Common/Config.cpp @@ -7,6 +7,7 @@ e2d::Config::Config() , _soundEnabled(true) , _frameInterval(15) , _showFps(false) + , _vSyncEnabled(false) , _outlineVisible(false) , _collisionEnabled(false) , _colliderVisible(false) @@ -28,6 +29,11 @@ void e2d::Config::showFps(bool show) _showFps = show; } +void e2d::Config::setVSyncEnabled(bool enabled) +{ + _vSyncEnabled = enabled; +} + void e2d::Config::setFrameInterval(int interval) { _frameInterval = interval; @@ -76,6 +82,11 @@ bool e2d::Config::isSoundEnabled() const return _soundEnabled; } +bool e2d::Config::isVSyncEnabled() const +{ + return _vSyncEnabled; +} + bool e2d::Config::isFpsShow() const { return _showFps; diff --git a/core/e2dbase.h b/core/e2dbase.h index a5d23c3e..4a9915bf 100644 --- a/core/e2dbase.h +++ b/core/e2dbase.h @@ -56,6 +56,8 @@ private: E2D_DISABLE_COPY(Game); + void __update(); + private: bool _quit; bool _paused; @@ -292,6 +294,9 @@ public: // 渲染游戏画面 void render(); + // 删除设备相关资源 + void discardDeviceResources(); + // 获取文字渲染器 TextRenderer * getTextRenderer(); @@ -326,12 +331,6 @@ private: E2D_DISABLE_COPY(Renderer); - // 创建设备相关资源 - bool __createDeviceResources(); - - // 删除设备相关资源 - void __discardDeviceResources(); - // 渲染 FPS void _renderFps(); diff --git a/core/e2dcommon.h b/core/e2dcommon.h index 2876a08c..ae9a8ccd 100644 --- a/core/e2dcommon.h +++ b/core/e2dcommon.h @@ -1065,6 +1065,12 @@ public: bool show ); + // 打开或关闭垂直同步 + // 默认:关闭 + void setVSyncEnabled( + bool enabled + ); + // 设置帧率刷新间隔 // 默认:15 void setFrameInterval( @@ -1113,6 +1119,9 @@ public: // 获取声音打开状态 bool isSoundEnabled() const; + // 获取垂直同步打开状态 + bool isVSyncEnabled() const; + // 获取 FPS 显示状态 bool isFpsShow() const; @@ -1136,6 +1145,7 @@ public: protected: bool _showFps; + bool _vSyncEnabled; bool _soundEnabled; bool _outlineVisible; bool _collisionEnabled;