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


本系列主要参考此博客的文章l,同时会加上一点个人实践过程。

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


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

 

The Structure of the GetMessage() Loop

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

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

【DirectX11-Tutorial】实时消息循环The Real-Time Message Loop_第1张图片

The Structure of a GetMessage() Loop

循环结构

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

 

A New Function, PeekMessage()

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


【DirectX11-Tutorial】实时消息循环The Real-Time Message Loop_第2张图片

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);
}

这一篇文章的内容并没有对之前的程序有明显的改变,因为只影响在改变窗口的时候。

 


你可能感兴趣的:(游戏,Win32,basic,VS2015,directx11)