您的位置:首页 > 运维架构

【DirectX11-Tutorial】实时消息循环The Real-Time Message Loop

2016-04-26 17:18 465 查看
本系列主要参考此博客的文章l,同时会加上一点个人实践过程。

========================================== 分割线 ==========================================

这篇文章主要了解单独的函数PeekMessage(),并谈一下与类似的GetMessage()函数有什么不同。GetMessage()也不是不好,只是没办法再游戏中取得持续卓越的效果所以考虑PeekMessage()函数代替前者。

The Structure of the GetMessage() Loop

上一篇文章中,使用GetMessage()函数创建了一个简单的窗口应用,同时结合另外两个函数创建处理系统发送消息的循环。但还有一些并未提及。

下面的关系图显示了事件循环的工作原理 ︰



The Structure of a GetMessage() Loop
循环结构
当创建窗口的时候,开始从GetMessage()函数中进入事件循环。Getmessage () 即处于等待消息状态,并在收到一个消息的时候将其发送到下一个函数中。系统程序的逻辑就是等待指令然后执行。然而这种逻辑并不适用于我们,当等待执行语句开始执行的时候,每秒需要创建30到60完全渲染的3D图像并且要毫无延迟的将这些图像传递到屏幕。如此我们遇到一个相当有趣的麻烦,因为系统无法以30/s的速度发送这些消息。

A New Function, PeekMessage()

解决这个问题的方式就是把 GetMessage()语句换为PeekMessage()。这个函数虽然执行同样的操作但是却有很重要的区别:它不需要等待就可以进行发送。PeekMessage()函数只看消息队列,检测消息队列是否有正在等待的任何消息,如果存在消息及发送到下一个函数,如果不存在则程序处理其他内容。



The Structure of a PeekMessage() Loop
以下是 PeekMessage()的函数原型:

BOOL PeekMessage(LPMSG lpMsg,

HWND hWnd,

UINT wMsgFilterMin,

UINT wMsgFilterMax,

UINT wRemoveMsg);


前四个参数与GetMessage()的参数相同,然而第五个wRemoveMsg参数是此函数特有的。

这个函数的作用是消息是否留在消息队列中。其决定参数为PM_REMOVE 或者PM_NOREMOVE。

以下是使用 PeekMessage()修改过的主循环:

// enter the main loop:

// this struct holds Windows event messages

MSG msg = {0};

// Enter the infinite message loop

while(TRUE)

{

// Check to see if any messages are waiting in the queue

if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

{

// translate keystroke messages into the right format

TranslateMessage(&msg);

// send the message to the WindowProc function

DispatchMessage(&msg);

// check to see if it's time to quit

if(msg.message == WM_QUIT)

break;

}

else

{

// Run game code here

// ...

// ...

}

}


while(TRUE)

将创建一个无限循环直至退出游戏。

if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))

因为不再等待消息,只是使用 PeekMessage()检测消息是否存在。如果有消息 PeekMessage() 返回 TRUE,如果没有返回FALSE。所以如果存在消息,它运行 TranslateMessage() 和 DispatchMessage(),否则继续代码程序。

if(msg.message == WM_QUIT)

如果消息结果是 WM_QUIT,这意味着退出"无限"的循环并返回。如果推出程序Getmessage () 返回 '0',从而结束 while() 循环。

Running the New Loop

以下是新修改的代码:

// include the basic windows header file
#include <windows.h>
#include <windowsx.h>

// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam);

// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// the handle for the window, filled by a function
HWND hWnd;
// this struct holds information for the window class
WNDCLASSEX wc;

// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));

// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = L"WindowClass1";

// register the window class
RegisterClassEx(&wc);

// calculate the size of the client area
RECT wr = {0, 0, 500, 400};    // set the size, but not the position
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);    // adjust the size

// create the window and use the result as the handle
hWnd = CreateWindowEx(NULL,
L"WindowClass1",    // name of the window class
L"Our First Windowed Program",    // title of the window
WS_OVERLAPPEDWINDOW,    // window style
300,    // x-position of the window
300,    // y-position of the window
wr.right - wr.left,    // width of the window
wr.bottom - wr.top,    // height of the window
NULL,    // we have no parent window, NULL
NULL,    // we aren't using menus, NULL
hInstance,    // application handle
NULL);    // used with multiple windows, NULL

// display the window on the screen
ShowWindow(hWnd, nCmdShow);

// enter the main loop:

// this struct holds Windows event messages
MSG msg = {0};

// Enter the infinite message loop
while(TRUE)
{
// Check to see if any messages are waiting in the queue
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// translate keystroke messages into the right format
TranslateMessage(&msg);

// send the message to the WindowProc function
DispatchMessage(&msg);

// check to see if it's time to quit
if(msg.message == WM_QUIT)
break;
}
else
{
// Run game code here
// ...
// ...
}
}

// return this part of the WM_QUIT message to Windows
return msg.wParam;
}

// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// sort through and find what code to run for the message given
switch(message)
{
// this message is read when the window is closed
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
} break;
}

// Handle any messages the switch statement didn't
return DefWindowProc (hWnd, message, wParam, lParam);
}


这一篇文章的内容并没有对之前的程序有明显的改变,因为只影响在改变窗口的时候。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: