本系列文章由@二货梦想家张程 所写,转载请注明出处。
本文章链接:http://blog.csdn.net/terence1212/article/details/44208419
作者:ZeeCoder 微博链接:http://weibo.com/zc463717263
我的邮箱:michealfloyd@126.com 欢迎大家发邮件来和我交流编程心得
you are what you read!与大家共勉!
-------------------------------------------------------分割线:ZeeCoder-----------------------------------------------
上一个学习笔记中写了用定时器来实现简易动画,但是在实际游戏编程开发中,往往需要游戏画面在一秒之内更新至少25次以上,这一秒钟内程序还必须进行消息的处理和大量数学运算甚至音效的输出等操作。如此看来,定时器往往满足不了这一需求。所以提出了游戏循环的概念,其基本思想是:判断其中的内容是否有当前要处理的消息,如果有则处理,否则按照设定的时间间隔来重绘画面。其代码如下:
<span style="font-size:12px;">//gamecircle GetMessage(&msg,NULL,NULL,NULL);//MSG初始化,如果没有初始化会报错 while ( msg.message != WM_QUIT)//如果窗口消息不是WM_QUIT,则继续运行循环 { //BOOL PeekMessage( //函数原型 // LPMSG IpMsg, //接受消息用的MSG指针 // HWND hWnd, //某消息被检查的窗口句柄 // UINT wMSGfilterMin, //指定被检查的消息范围里的第一个消息 // UINT wMsgFilterMax, //指定被检查的消息范围里的最后一个消息 // UINT wRemoveMsg //确定消息如何被处理 // ); if ( PeekMessage( &msg , NULL ,0 ,0 ,PM_REMOVE))//PM_REMOVE消息从队列里除掉 { TranslateMessage( &msg); DispatchMessage(&msg); } else { tNow = GetTickCount(); if (tNow - tPre >= 100) //相差0.1秒时在进行重绘操作 MyPaint(hdc); } }</span>
上述代码理解后就可以进行游戏循环的编程了。来看具体代码
1、声明全局变量
// Global Variables: HINSTANCE hInst; // current instance TCHAR szTitle[MAX_LOADSTRING]; // The title bar text TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name HBITMAP walker[16]; HDC hdc , mdc ; HWND hwnd; DWORD tPre , tNow ,tCheck; //tPre记录上一次的绘图时间,tNow记录此次准备绘图的时间,tCheck记录每秒开始的时间 int num ,frame ,fps;//num记录图号,frame用来累加每次画面更新的次数,fps记录每秒画面更新的次数
2、主函数
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // TODO: Place code here. MSG msg; //HACCEL hAccelTable; // Initialize global strings LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_GAMECIRCLE, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } ////gamecircle GetMessage(&msg,NULL,NULL,NULL);//MSG初始化,如果没有初始化会报错 while ( msg.message != WM_QUIT) { //BOOL PeekMessage( // LPMSG IpMsg, //接受消息用的MSG指针 // HWND hWnd, //某消息被检查的窗口句柄 // UINT wMSGfilterMin, //指定被检查的消息范围里的第一个消息 // UINT wMsgFilterMax, //指定被检查的消息范围里的最后一个消息 // UINT wRemoveMsg //确定消息如何被处理 // ); if ( PeekMessage( &msg , NULL ,0 ,0 ,PM_REMOVE))//PM_REMOVE消息从队列里除掉 { TranslateMessage( &msg); DispatchMessage(&msg); } else { tNow = GetTickCount(); if (tNow - tPre >= 100) //相差0.1秒时在进行重绘操作 MyPaint(hdc); } }
3、自定义绘图函数
void MyPaint(HDC hdc) { TCHAR str[40]; if (num == 15) num =0; frame++; //更新次数加1 if (tNow - tCheck >= 1000) { fps = frame; frame = 0 ; tCheck = tNow; } SelectObject(mdc , walker[num]); _stprintf_s(str , TEXT("每秒显示%d个画面") ,fps ); TextOut(mdc , 0 ,0 , str , _tcslen(str)); BitBlt(hdc , 0 ,0 ,600 ,450 , mdc , 0 , 0 ,SRCCOPY); tPre = GetTickCount(); //记录此次绘图时间 num++; }
4、初始化函数
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; TCHAR filename[20] ; hInst = hInstance; // Store instance handle in our global variable hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } MoveWindow(hWnd , 10 ,10 ,600 ,450 ,true); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); hdc = GetDC(hWnd); mdc = CreateCompatibleDC(hdc); int i; //载入各个人物位图 for ( i = 0 ; i <= 15 ;i++) { _stprintf_s(filename , TEXT("%d.bmp") , i); walker[i] = (HBITMAP)LoadImage(NULL , filename , IMAGE_BITMAP , 121 ,129, LR_LOADFROMFILE); } num = 0 ; frame = 0 ; MyPaint(hdc); return TRUE; }
5、实现效果:
我们设定的画面更新时间是0.1秒,那么每秒中最多更新10次。
笔记三就写到这里了,还是那句话,欢迎大家发邮件和我交流学习~也请继续关注我的学习笔记~
学习游戏编程的路还很长,我还没有入门,望继续坚持下去,自我勉励~
end~