游戏的基石: 窗口 的建立


  Welcome back!很高兴再次与你相遇教程。废话不多说,继续。 


  上次的代码片段,说实在,拿在手里没有用。为啥?因为不能运行的啊:)我们这次就按照上次的安排,讲如何将显示图片的代码片段整合到程序中,让它能够具体的体现出来。 


  我将在这儿讨论 Windows 编程,而不是 MFC 。关于 MFC 和 Windows 的不同和各自的优点,我们不多涉及了。 MFC 就是微软的一个封装开发库,极大程度的降低了 Windows 开发的复杂。但是,我们还是继续 Windows 编程,呵呵。 


  我们来看,一个基本的 Windows 程序是一个窗口对吧:)我们所玩的游戏,其实也是有窗口的,只不过是看不见的,而且被 DirectDraw 掩盖了而已。那么,如何创建一个窗口呢?我们来看: 


BOOL Init(HINSTANCE hInst, int nCmdShow) 

{

    HWND hWnd;                           // 窗口的句柄,就是一个储存窗口的对象 

    WNDCLASS WndClass;                   // 用于注册窗口的对象 


    WndClass.style = CS_HREDRAW | CS_VREDRAW; // 定义窗口的类型 

    WndClass.lpfnWndProc = WinProc;      // 指定了窗口消息的处理函数 ** 关键! 

    WndClass.cbClsExtra = 0;             // 没有特定意义 

    WndClass.cbWndExtra = 0;             // 没有特定意义 

    WndClass.hInstance = hInst;          // 窗口的实例 

    WndClass.hIcon = LoadIcon(hInst, IDI_APPLICATION); // 指定窗口的图标 

    WndClass.hCursor = LoadCursor(hInst, IDC_ARROW);   // 指定程序的指针 

    WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // 指定背景色为黑色 

    WndClass.lpszMenuName = NULL;        // 指定菜单为无,游戏不需要 

    WndClass.lpszClassName = "GDIM_GAME_ENGINE"; //这个程序注册的名字 

    RegisterClass(&WndClass);            // 注册程序 


    hWnd = CreateWindowEx(WS_EX_TOPMOST, "GDIM_GAME_ENGINE", "GDIM_GAME", WS_POPUP, 112, 84, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInst, NULL); 

    // 这段代码就是实现了一个窗口的创建 

    // 我们可以通过来检测是否创建成功。如果失败将返回一个 FALSE 的值。 

    if(!hWnd) return FALSE; 

    ShowWindow(hWnd, nCmdShow);  // 显示窗口 

    UpdateWindow(hWnd);          // 更新窗口 


  好了,到这儿呢,我们就成功的创建了一个窗口。我们回头看我注了“**”的地方,关于这个函数,我们得写个同名函数来处理 Windows 的消息。呵呵,不好意思,再看一个函数: 


BOOL bActive = FALSE;        // 用于判断程序是否运行的变量 


long PASCAL WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

    switch(message) 

    { 

    case WM_ACTIVATE: 

        bActive = TRUE;      // 当程序被激活时,赋值 TRUE 

        break; 

    case WM_SETCURSOR: 

        SetCursor(NULL);     // 设定鼠标为不显示 

        return TRUE; 

    case WM_KEYDOWN: 

        switch(wParam) 

        {

        case VK_ESCAPE:      // 处理按下 ESC 键的反应 

            PostMessage(hWnd, WM_CLOSE, 0, 0);   // 发送一个关闭窗口的命令 

            break; 

        }

        break; 

    case WM_DESTROY:         // 在窗口即将销毁时的反应 

        PostQuitMessage(0);  // 发送一个结束的消息,必须的! 

        break;

    } 

    return DefWindowProc(hWnd, message, wParam, lParam);  // 一些没有像上面一样具体定义的消息的处理 


  这个函数就是用来处理 Windows 的消息的,是一个标准程序必要的。 


  再来最后一个重要的函数。不好意思哦,实在是不想这么写,但是想想,在这个函数结束后,你就可以实现一个具体的窗口了哦:) 


int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow)

    MSG msg; // 定义一个消息的对象 


    if(!Init(hInst, nCmdShow)) return FALSE;           // 还记得上面的那个函数吗? 


    while(1) // 程序的循环 

    { 

        if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) // 不要特别注意的 

        { 

            if(!GetMessage(&msg, NULL, 0, 0 )) 

            return msg.wParam; 

            TranslateMessage(&msg); 

            DispatchMessage(&msg); 

        } 

        else if(bActive)     // 就是上面的“程序是否激活”的变量判断 

        { 

            ShowThePic();    // 显示人物图片的函数,上节的内容,就是整合在这儿的! 

        } 

        else WaitMessage();  // 没有消息时,就等消息:) 

    } 


  其实到这儿,一个简单的程序已经可以出炉了:)编译,运行,你将看到一个黑色的窗口。这个窗口不同于一般的窗口,它没有平常的标题栏,这个才是适合我们游戏的。我在这儿给出完整的代码,但是,无法将上节的内容以程序的形式表现出来,因为涉及到了 DirectDraw 。我不想过多在教程中涉及未讲的知识,因为那样会影响对现有知识的理解。 


  下章教程,我将开始介绍 DirectDraw 了,以便能尽快将显示的内容整合,同时我会保持教程和代码的详尽。 


注:

  本范例在以下环境中通过:VC6.0、DirectX 7.0/8.1 SDK、Win2000/WinXP