// 这是我研究的游戏循环框架的多线程版,注释过得代码是用来测试的。
#include <Windows.h>
#include <tchar.h>
#include <imm.h>
#pragma comment(lib, "WinMM")
#pragma comment(lib, "Imm32")
// 窗口句柄
HWND hWnd;
// 游戏运行状态
auto isRunning = true;
// 游戏线程精度
const auto PROID = 1U;
// 游戏帧率
const auto FPS = 60;
// 游戏分辨率
const auto WIDTH = 800, HEIGTH = 600;
// 窗口输入法句柄(以便需要时启用输入法)
HIMC hImc;
// 定义游戏窗口
const struct DLGTEMPLATEEX
{
::DLGTEMPLATE Dlg;
::WCHAR Menu;
::WCHAR Class;
::WCHAR Title;
} DT = {
WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU | DS_CENTER
, WS_EX_APPWINDOW, 0, 0, 0, WIDTH >> 1, HEIGTH >> 1};
// 游戏窗口回调
INT_PTR CALLBACK MainProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
// 游戏线程(处理游戏逻辑)
TIMECALLBACK MainGame;
// 主线程(处理窗口消息)
INT APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, INT nShowCmd)
{
return DialogBoxIndirect(hInstance, &DT.Dlg, HWND_DESKTOP, MainProc);
}
INT_PTR CALLBACK MainProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_INITDIALOG:
// 防止游戏窗口受显示参数影响
DefWindowProc(::hWnd = hWnd, WM_SYSCOMMAND, SC_RESTORE, NULL);
// 禁用输入法
hImc = ImmAssociateContext(hWnd, nullptr);
// 创建游戏线程
timeSetEvent(PROID, PROID, MainGame, GetCurrentThreadId(), TIME_ONESHOT);
break;
case WM_CLOSE:
// 结束对话框
EndDialog(hWnd, EXIT_SUCCESS);
// 判断游戏循环是否已经退出
if (isRunning)
{
// 通知游戏线程退出
isRunning = false;
// 等待游戏线程退出
SuspendThread(GetCurrentThread());
}
break;
case WM_SYSCOMMAND:
switch (LOWORD(wParam))
{
// 拦截Alt菜单
case SC_KEYMENU:
// 拦截屏保
case SC_SCREENSAVE:
// 拦截黑屏
case SC_MONITORPOWER:
break;
default:
return FALSE;
}
break;
// 屏蔽窗口客户群刷新
case WM_ERASEBKGND:
break;
default:
return FALSE;
}
return TRUE;
}
bool InitGame();
bool UpdataGame();
void ExitGame();
void CALLBACK MainGame(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
{
LARGE_INTEGER cur, old, fre;
LONGLONG frame = 1LL;
// 提高游戏线程优先级
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
// 游戏初始化
InitGame();
QueryPerformanceFrequency(&fre);
QueryPerformanceCounter(&old);
// 游戏循环
while (isRunning)
{
QueryPerformanceCounter(&cur);
if ((cur.QuadPart - old.QuadPart) * FPS >= fre.QuadPart * frame)
{
++frame;
// 更新游戏
if (UpdataGame())
{
PostMessage(hWnd, WM_CLOSE, NULL, NULL);
break;
}
// 让出CPU给其它线程
SwitchToThread();
continue;
}
// 延时并降低等待更新的CPU占用
Sleep(PROID);
}
// 结束游戏
ExitGame();
HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME, FALSE, dwUser);
isRunning = false;
ResumeThread(hThread);
CloseHandle(hThread);
}
HDC hDC, hBufDC;
//DWORD dwTime;
bool InitGame()
{
// 创建缓冲区
hDC = GetDC(hWnd);
hBufDC = CreateCompatibleDC(nullptr);
HBITMAP hBmp = CreateCompatibleBitmap(hDC, WIDTH, HEIGTH);
SelectObject(hBufDC, hBmp);
DeleteObject(hBmp);
PatBlt(hDC, 0, 0, WIDTH, HEIGTH, BLACKNESS);
//dwTime = timeGetTime();
return{};
}
bool UpdataGame()
{
//TCHAR str[100];
//static int i = {};
//DWORD dt = timeGetTime();
//int len = _stprintf(str, TEXT("time: %lf, frame: %d, fps: %lf"), ++i / double(FPS), i, i * 1000 / double(dt - dwTime) + .005);
//TextOut(hBufDC, 100, 100, str, len);
// 刷新缓冲区到窗口
BitBlt(hDC, 0, 0, WIDTH, HEIGTH, hBufDC, 0, 0, SRCCOPY);
// 按Esc退出
return GetAsyncKeyState(VK_ESCAPE) < 0;
}
void ExitGame()
{
DeleteDC(hBufDC);
ReleaseDC(hWnd, hDC);
}
2014年12月20日 17点12分
12
![[冷]](/static/emoticons/u51b7.png)
改变优先级大丈夫?
2014年12月20日 18点12分
回复 白晓生锄禾 :嗯,是啊。
2014年12月21日 05点12分