当前位置:编程学习 > VC++ >>

(Visual C++)游戏开发笔记之八——基础动画显示(二)游戏循环的使用

在笔记七中我们讲解了用定时器来产生动画的效果。定时器的使用固然简单方便,但是事实上这样的方法仅适合用在显示简易动画及小型的游戏程序中。因为一般而言,游戏本身需要显示顺畅的游戏画面,使玩家感觉不到延迟的状态。基本游戏画面必须在一秒钟之内更新至少25次以上,这一秒钟内程序还必须进行消息的处理和大量数学运算甚至音效的输出等操作。而使用定时器的消息来驱动这些操作,往往达不到所要求的标准,不然就会产生画面显示不顺畅和游戏响应时间太长的情况。

 


这里我们提出一种游戏循环的概念,游戏循环是将原先程序中的消息循环加以修改,方法是判断其中的内容目前是否有要处理的消息,如果有则进行处理,否则按照设定的时间间隔来重绘画面。下面是接下来一段游戏循环的程序代码:


[cpp]
//游戏循环  
    while( msg.message!=WM_QUIT )               //注释点1(详细内容见下)  
    { 
        if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )       //注释点2(详细内容见下)  
        { 
            TranslateMessage( &msg ); 
            DispatchMessage( &msg ); 
        } 
else 

tNow = GetTickCount();                        //注释点3  
if(tNow-tPre >= 100)                   //注释点4  
MyPaint(hdc); 

    } 
//游戏循环
    while( msg.message!=WM_QUIT )               //注释点1(详细内容见下)
    {
        if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) )       //注释点2(详细内容见下)
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
else
{
tNow = GetTickCount();                        //注释点3
if(tNow-tPre >= 100)                   //注释点4
MyPaint(hdc);
}
    }

 

我们来讲解一下游戏循环片段中的几个重点。

<1>注释点1:当收到的msg.message不是窗口结束消息WM_QUIT,则继续运行循环,其中msg是一个MSG的消息结构,其结构成员message则是一个消息类型的代号。

 


<2>注释点2:使用PeekMessage()函数来检测目前是否有需要处理的消息,若检测到消息(包含WM_QUIT消息)则会返回一个非“0”值,否则返回“0”。因此在游戏循环中,若检测到消息便进行消息的处理,否则运行else叙述之后的程序代码。这里我们要注意的是,PeekMessage()函数不能用原先消息循环的条件GetMessage()取代,因为GetMessage()函数只有在取得WM_QUIT消息时才会返回"0",其他时候则是返回非“0”值或“-1”(发生错误时)

 


<3>注释点3:GetTickCount()函数会取得系统开始运行到目前所经过的时间,单位是毫秒(milliseconds)。  之前我理解错了,在这里感谢worldy的指出我的错误。

DWORD GetTickCount()    //取得系统开始到目前经过的时间

这里取得时间的目的主要是可以搭配接下来的判断式,用来调整游戏运行的速度,使得游戏不会因为运行计算机速度的不同而跑得太快或者太慢。

 


<4>注释点4:if条件式中,"tPre"记录前次绘图的时间,而“tNow-tRre”则是计算上次绘图到这次循环运行之间相差多少时间。这里设置为若相差40个单位时间以上则再次进行绘图的操作,通过这个数值的控制可以调整游戏运行的速度。这里设定40个单位时间(微秒)的原因是,因为每隔40个单位进行一次绘图的操作,那么1秒钟大约重绘窗口1000/40=25次刚好可以达到期望值。

由于循环的运行速度远比定时器发出时间信号来得快,因此使用游戏循环可以更精准地控制程序运行速度并提高每秒钟画面重绘的次数。

 

了解了游戏循环使用的基本概念之后,接下来的范例将以游戏循环的方法进行窗口的连续贴图,更精确地制作游戏动画效果。


[cpp]
#include "stdafx.h"  
#include <stdio.h>  
//全局变量声明  
HINSTANCE hInst; 
HBITMAP man[7]; 
HDC  hdc,mdc; 
HWND    hWnd; 
DWORD   tPre,tNow,tCheck;                 //声明三个函数来记录时间,tPre记录上一次绘图的时间,tNow记录此次准备绘图的时间,tCheck记录每秒开始的时间  
int  num,frame,fps;                    //num用来记录图号,frame用来累加每次画面更新的次数,fps(frame per second)用来记录每秒画面更新的次数  
//全局函数的声明  
ATOM     MyRegisterClass 
(HINSTANCE hInstance); 
BOOL     InitInstance 
(HINSTANCE, int); 
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM,  
LPARAM); 
void     MyPaint(HDC hdc); 
//***WinMain函数,程序入口点函数**************************************  
int APIENTRY WinMain(HINSTANCE hInstance, 
                     HINSTANCE hPrevInstance, 
                     LPSTR     lpCmdLine, 
                     int       nCmdShow) 

MSG msg; 
MyRegisterClass(hInstance); 
//运行初始化函数  
if (!InitInstance (hInstance, nCmdShow))  

return FALSE; 

#include "stdafx.h"
#include <stdio.h>
//全局变量声明
HINSTANCE hInst;
HBITMAP man[7];
HDC  hdc,mdc;
HWND hWnd;
DWORD tPre,tNow,tCheck;                 //声明三个函数来记录时间,tPre记录上一次绘图的时间,tNow记录此次准备绘图的时间,tCheck记录每秒开始的时间
int  num,frame,fps;                    //num用来记录图号,frame用来累加每次画面更新的次数,fps(frame per second)用来记录每秒画面更新的次数
//全局函数的声明
ATOM  MyRegisterClass
(HINSTANCE hInstance);
BOOL  InitInstance
(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);
void  MyPaint(HDC hdc);
//***WinMain函数,程序入口点函数**************************************
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
       &nbs

补充:软件开发 , Vc ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,