DirectX游戏编程入门——第一部分(Windows和DirectX游戏编程引言) —— 游戏循环...

本系列文章由 net_assassin 编写,转载请注明出处。

http://blog.youkuaiyun.com/net_assassin/article/category/1100363


作者:net_assassin 邮箱: net_assassin@hotmail.com 期待着与志同道合的朋友们相互交流

windows编程比我们在之前所讲的要博大精深的多,我们所需关注的只是能够让DirectX启动起来的有限代码。一个“真正”的Windows应用程序应该有一个菜单、一个状态栏、一个工具栏及许多对话框,这也是一般的Windows编程书籍又大又后的原因。我们这里要关注的是游戏的创建而不是将大量篇幅花费在操作系统的逻辑上。

我们先来看标准的 WinMain函数:

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
MyRegisterClass(hInstance);
if(!InintInstance(hInstance,nCmdShow))
return FALSE;
while(GetMessage(&msg,NULL,0,0))
{
       TranslateMessage(&msg);
       DispatchMessage(&msg);
}
return msg.wParam;
}

这个版本的WinMain 仅有一个问题:它没有一个连续的循环,只有一个有限的循环用于处理任何尚未处理的消息,然后退出。(while那一行)。

实时游戏循环

上面列出的是一个蠢笨的、无生命力的WinMain版本,完全不适合于游戏。这个版本中的while循环是事件驱动的。我们需要的是一个能够持续运行而无论是否有事件消息进来。创建一个无论Windows在做什么都能一直运行的实时循环的关键就在于修改WinMain 中的while循环。
-------------------------------------------------------> 图片资源来自51CTO.com
我们的目的是要构造一个无限的实时循环,为了达到这一目的,我们要将函数GetMessage 替换为 PeekMessage。
好,在这里,我们停一停,讲解一下这两个函数的区别:

1.GetMessage将等到有合适的消息时才返回,而PeekMessage只是撇一下消息队列。

2.GetMessage会将消息从队列中删除,而PeekMessage可以设置最后一个参数wRemoveMsg来决定是否将消息保留在队列中。

在Windows的内部,GetMessage和PeekMessage执行着相同的代码。而两者最大的不同之处则体现在没有任何消息返回到应用程序的情况下。在此种情况下,PeekMessage会返回一个空值到应用程序,GetMessage会在此时让应用程序休眠。

游戏循环

将PeekMessage插到WinMain中,得到新版本的WinMain。
bool gameover = false;
whlie(!gameover)
{
      if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
      {
              //hand any event message
              TranslateMessage(&msg);
              DispatchMessage(&msg);
       }
       //process game loop
       Game_Run();
}

一个GameLoop项目:


这段程序实现在窗口上实时绘制位图。
源代码如下:
/**
    Beginning Game Programming, Third Edition
    Chapter 2
    GameLoop project
**/

#include <windows.h>
#include <iostream>
#include <time.h>
using namespace std;

const string APPTITLE = "Game Loop";
HWND window;
HDC device;
bool gameover = false;


/**
 ** Loads and draws a bitmap from a file and then frees the memory
 ** 必须承认的是这个函数很慢,这个函数适合于装载完整的背景图片
 ** 或者只需将图片绘制一次的小位图。这个函数将位图文件装入内存
 **/
void DrawBitmap(char *filename, int x, int y)                                       
{																					
    //load the bitmap image
    HBITMAP image = (HBITMAP)LoadImage(0,"c.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);

    //read the bitmap's properties
    BITMAP bm;
    GetObject(image, sizeof(BITMAP), &bm);

    //create a device context for the bitmap
    HDC hdcImage = CreateCompatibleDC(device);
    SelectObject(hdcImage, image);

    //draw the bitmap to the window (bit block transfer)
    BitBlt( 
        device,                  //destination device context
        x, y,                    //x,y location on destination
        bm.bmWidth, bm.bmHeight, //width,height of source bitmap
        hdcImage,                  //source bitmap device context
        0, 0,                    //start x,y on source bitmap
        SRCCOPY);                //blit method

    //delete the device context and bitmap
    DeleteDC(hdcImage);
    DeleteObject((HBITMAP)image);
}

/**
 ** Startup and loading code goes here
 **/
bool Game_Init()
{
    //start up the random number generator
    srand(time(NULL));

    return 1;
}

/**
 ** Update function called from inside game loop
 **/
void Game_Run()
{
    if (gameover == true) return;

    //get the drawing surface
    RECT rect;
    GetClientRect(window, &rect);

    //draw bitmap at random location
    int x = rand() % (rect.right - rect.left);
    int y = rand() % (rect.bottom - rect.top);
    DrawBitmap("c.bmp", x, y);
}

/**
 ** Shutdown code
 **/
void Game_End()
{
    //free the device
    ReleaseDC(window, device);
}

/**
 ** Window callback function
 **/
LRESULT CALLBACK WinProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) 
    {
        case WM_DESTROY:
            gameover = true;
            PostQuitMessage(0);
            break;
    }
    return DefWindowProc(hWnd, message, wParam, lParam);
}

/**
 ** MyRegiserClass function sets program window properties
 **/
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    //create the window class structure
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX); 

    //fill the struct with info
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = (WNDPROC)WinProc;
    wc.cbClsExtra     = 0;
    wc.cbWndExtra     = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = APPTITLE.c_str();
    wc.hIconSm       = NULL;

    //set up the window with the class info
    return RegisterClassEx(&wc);
}

/**
 ** Helper function to create the window and refresh it
 **/
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    //create a new window
    window = CreateWindow(
       APPTITLE.c_str(),              //window class
       APPTITLE.c_str(),              //title bar
       WS_OVERLAPPEDWINDOW,   //window style
       CW_USEDEFAULT,         //x position of window
       CW_USEDEFAULT,         //y position of window
       640,                   //width of the window
       480,                   //height of the window
       NULL,                  //parent window
       NULL,                  //menu
       hInstance,             //application instance
       NULL);                 //window parameters

    //was there an error creating the window?
    if (window == 0) return 0;

    //display the window
    ShowWindow(window, nCmdShow);
    UpdateWindow(window);

    //get device context for drawing
    device = GetDC(window);

    return 1;
}

/**
 ** Entry point function
 **/
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;

    //create window
    MyRegisterClass(hInstance);
    if (!InitInstance (hInstance, nCmdShow)) return 0;

    //initialize the game
    if (!Game_Init()) return 0;

    // main message loop
    while (!gameover)
    {
        //process Windows events
        if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        
        //process game loop
        Game_Run();
    }

    //free game resources
    Game_End();

    return msg.wParam;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值