Win32+Direct3D 11游戏窗口拖动/调整时保持运行的实现方案
解决Win32+Direct3D11拖动窗口时游戏暂停的问题
问题背景
拖动或调整游戏窗口时,系统触发WM_ENTERSIZEMOVE消息后会进入模态消息循环,阻塞游戏主循环导致游戏暂停。对于依赖实时反应的游戏,玩家可通过反复触发该行为作弊,因此需要实现拖动/调整窗口时游戏持续运行并支持操控。
解决方案
1. 添加状态标记
在全局或游戏类中定义布尔变量,标记窗口是否处于拖动/调整状态:
bool g_isResizingOrMoving = false;
2. 修改窗口过程拦截状态消息
在WndProc中捕获WM_ENTERSIZEMOVE和WM_EXITSIZEMOVE,更新状态标记并跳过系统默认处理(避免进入模态循环),同时处理WM_SIZE消息保证D3D渲染正常:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_CLOSE: DestroyWindow(hwnd); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; case WM_ENTERSIZEMOVE: g_isResizingOrMoving = true; return 0; // 跳过系统默认模态循环 case WM_EXITSIZEMOVE: g_isResizingOrMoving = false; return 0; // 恢复正常状态 case WM_SIZE: if (g_pd3dDevice != nullptr && wParam != SIZE_MINIMIZED) { // 此处添加D3D交换链重置、视口调整逻辑 // 示例: // HRESULT hr = g_pSwapChain->ResizeBuffers(0, LOWORD(lParam), HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0); // 后续更新视口、渲染目标等操作 } return 0; } return DefWindowProcW(hwnd, message, wParam, lParam); }
3. 修改游戏主循环,维持拖动时的游戏运行
在主循环中,无论窗口是否处于拖动状态,持续处理消息并执行游戏逻辑;拖动期间主动处理鼠标消息,保证窗口交互流畅:
MSG msg = {}; while (msg.message != WM_QUIT) { // 处理所有待处理的消息 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessageW(&msg); if (msg.message == WM_QUIT) { goto ExitLoop; } } // 执行游戏逻辑与渲染(不受拖动状态影响) // code of the game (rendering and mechanics) // 拖动期间主动处理鼠标消息,维持窗口拖动行为 if (g_isResizingOrMoving) { MSG dragMsg; while (PeekMessage(&dragMsg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { if (GetMessage(&dragMsg, NULL, 0, 0)) { TranslateMessage(&dragMsg); DispatchMessageW(&dragMsg); } } } } ExitLoop:
注意事项
- 必须正确处理
WM_SIZE消息,否则窗口调整后会出现渲染异常。 - 拖动期间避免执行过于繁重的逻辑,保证窗口交互流畅性。
- 若使用游戏类封装状态,需将全局标记替换为类成员变量。
内容的提问来源于stack exchange,提问作者M 027
相关产品推荐
相关产品推荐

