前面在制作GDI游戏动画基础的时候就谈过定时器这种消息驱动的方式并不能达到显示顺畅游戏画面的要求。因此各种编程书籍都会提及一个所谓“游戏循环”的概念。
而在windows 游戏编程中,这个概念主要是通过PeekMessage这个API来实现的。回忆此前Windows 默认的消息循环,是通过GetMessage来实现的,那么理清楚这两个APi之间的区别,就能理解Windows游戏循环的概念了。
“在Windows内部,GetMessage和PeekMessage执行相同的代码,而两者最大的不同之处体现在没有消息返回到应用程序的情况下。PeekMessage会返回一个空值到应用程序,而GetMessage会在此时让应用程序休眠。”
了解了上面这个特性,为了达到游戏画面在一秒钟之内更新至少25次以上,那么就知道应该利用PeekMessage在空闲的时候也能利用程序来进行刷新操作。
这样就可以将之前GDI游戏动画基础中用Windows定时器做动画效果的例子修改为“游戏循环”的方式,然后对比一下两种方式的效果。
关键代码:
//add by leo
HBITMAP g_hBitmapMan[12];//位图数组,用于存放人物位图
HDC g_mdc,g_hdc; //mdc为内存兼容DC,hdc用来存储窗口DC
HWND g_hWnd;
DWORD g_dwTimePre, g_dwTimeNow, g_dwTimeCheck;//分别记录上一次绘图时间,此次绘图时间,每秒开始时间
int g_nNum, g_nFrame, g_nfps; //分别记录图索引,累加画面更新次数,每秒帧数
..........................................................
修改windows消息循环
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
//游戏循环
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
g_dwTimeNow = GetTickCount();
if (g_dwTimeNow - g_dwTimePre >= 100)
{
AnimaPaint(g_hdc);
}
}
}
............................................................
void AnimaPaint(HDC hdc)
{
if (g_nNum > 12)
{
g_nNum = 0;
}
//计算每秒帧数
g_nFrame++;
if (g_dwTimeNow - g_dwTimeCheck >= 1000)
{
g_nfps = g_nFrame;
g_nFrame = 0;
g_dwTimeCheck = g_dwTimeNow;
}
SelectObject(g_mdc, g_hBitmapMan[g_nNum]);
BitBlt(hdc, 0, 0, 640, 480, g_mdc, 0, 0, SRCCOPY);
//记录此次画图时间
g_dwTimePre = GetTickCount();
g_nNum++;
}