一般合适的游 戏运行速度是 30fps 左右,就是 30 幅画每秒。如果速度低了,动画就不连续。 定时,就是要使游戏的处理速度固定在 30fps 左右。当然,前提条件是程序本身的执行速度 要大于 30fps,否则就没有限制这一说了。如果程序本身的执行速度小于 30fps,那么就要考虑 改善算法,以提高程序本身的执行速度,或者选择配置更高的计算机来运行。就目前而言,家用 计算机的运行速度基本上可以满足我们的程序,所以这个限制并不是问题。 注意 在游戏编程中,以程序执行速度为第一,目的在于:速度快了,可以简单的调低;如果慢了,麻烦 就大了。 定时有几种办法。 一种就像下一节中的, 使用 Sleep 或者 delay 函数。 这个方法比较简单, 但是有很大的弊端。 就是只是让计算机停顿了一段固定的时间,而没有考虑到程序本身的执行速度。如果换了另一台 计算机,就会应为计算机速度不同而造成程序执行时间不同,从而使定时无效。 另一种方法是使用定时器。在代码执行之前,建立一个定时器,在代码执行之后,看看是否 到了时间,如果不到,停顿,直到规定的时间才往后执行,如: ………………………………………. StarTime = GetTickCount ( ) ; ……………………….. while ( (GetTickCount( ) – StarTime ) < 33 ) ……………………………………….. GetTickCount 函数用于获取系统时钟,记录开始的时间,然后执行需要的代码。第二次循 环之前,再次获取系统时钟,看看与前一次的差是否小于 33 毫秒,就是 30fps,如果不到,空 等。对于 DirextX 游戏,比较习惯用第二种方法,这在后面的章节中会应用到,这里就不在多说 了。现在只要有个印象就可以了,到实际应用的时候就会体会到。 一个基于 GDI 的游戏 在章末,给出一个基于 GDI 编程的游戏,基本上包括了本章的所有内容,可以方便大家深入 认识本章的知识。 注意,这个游戏使用了图标和光标,大家可以自己定义。游戏为一个相当粗糙的射击游戏, 只是为了说明一些基本的东西,DirectX 游戏就大不一样了,大家可以记住,最后再作一个比较。 Windows 下的 C/C++编程 当然,如果愿意,可以在这个基础上作一些修改。比如规定窗口大小,定义背景色,修饰一 下画面,改善一下算法等,也可以把它作得有声有色。 #include #include #include #include #include"Cursor_res.h" int x,y,x1; int i=0,n=0; int alln=1,shot=0; int level=0; HWND mainhwnd; LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); int Game_Main(void); int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow) { static TCHAR szAppName[]=TEXT("Shot"); static TCHAR szClassName[]=TEXT("ShotClass"); HWND hwnd; MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(CURSOR_CROSS)); wndclass.hCursor = LoadCursor(hInstance,MAKEINTRESOURCE(CURSOR_CROSS)); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szClassName; if(!RegisterClass(&wndclass)) { MessageBox(NULL,TEXT("This program requires Windows NT !"), szAppName,MB_ICONERROR); return 0; Windows 下的 C/C++编程 } hwnd = CreateWindow(szClassName, TEXT("The Shot Test Program"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); mainhwnd=hwnd; while(TRUE) { // test if there is a message in queue, if so get it if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { // test if this is a quit if (msg.message == WM_QUIT) break; // translate any accelerator keys TranslateMessage(&msg); // send the message to the window proc DispatchMessage(&msg); } // end if // main game processing goes here Game_Main(); } // end while return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { HDC hdc; RECT rect; hdc=GetDC(mainhwnd); switch(message) { Windows 下的 C/C++编程 case WM_CREATE: PAINTSTRUCT ps; static HPEN hpen; hpen = CreatePen(PS_SOLID,1,RGB(255,0,0)); return 0; case WM_LBUTTONDOWN: GetClientRect(mainhwnd,&rect); int k; SelectObject(hdc,hpen); if( LOWORD(lParam) > x-10 && LOWORD(lParam) < x+10&& HIWORD(lParam) > i && HIWORD(lParam) < i+20) { MessageBeep(MB_OK); i=0; shot++; alln++; x = rand()%500+10; if (shot >= 10) { level++; shot = 0; alln = 0; } for(k=0;k<20;k++) { Ellipse(hdc,LOWORD(lParam)-k,HIWORD(lParam)-k,LOWORD(lParam)+k,HIWORD(lParam)+k); Sleep(1); } Static HBRUSH hbrt = CreateSolidBrush(RGB(255,255,255)); SelectObject(hdc,hbrt); rect.left rect.top rect.right = LOWORD(lParam)-k-5; = HIWORD(lParam)-k-5; = LOWORD(lParam)+k+5; rect.bottom = HIWORD(lParam)+k+5; FrameRect(hdc,&rect,hbrt); FillRect(hdc,&rect,hbrt); SelectObject(hdc,GetStockObject(WHITE_BRUSH)); DeleteObject(hbrt); } return 0; Windows 下的 C/C++编程 case WM_PAINT: hdc=BeginPaint(hwnd,&ps); GetClientRect(hwnd,&rect); DrawText(hdc,TEXT("Shot Test !"),-1,&rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd,&ps); return 0; case WM_DESTROY: SelectObject(hdc,GetStockObject(BLACK_PEN)); DeleteObject(hpen); PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,message,wParam,lParam); } int Game_Main(void) { HDC hdc; RECT rect; static HBRUSH hbrush; static HBRUSH hbr; hdc=GetDC(mainhwnd); GetClientRect(mainhwnd,&rect); if( n == 0) { x = rand()%500+10; n++; } hbrush= CreateSolidBrush(RGB(255,0,0)); SelectObject(hdc,hbrush); Rectangle(hdc,x-10,i,x+10,i+20); DeleteObject(hbrush); Sleep(10); rect.top rect.left rect.right = i; = x-15; = x+15; rect.bottom = i+25; hbrush= CreateSolidBrush(RGB(255,255,255)); Windows 下的 C/C++编程 SelectObject(hdc,hbrush); FrameRect(hdc,&rect,hbrush); FillRect(hdc,&rect,hbrush); SelectObject(hdc,GetStockObject(WHITE_BRUSH)); if (level == 0) i++; if (level == 1) i+=2; if (level == 2) i+=3; if (level == 3) i+=5; if (level >= 4) i+=8; DeleteObject(hbrush); MoveToEx(hdc,0,300,NULL); LineTo(hdc,550,300); char szBuffer[128]; sprintf(szBuffer,"Total: %d / if( i > 300) { n=0; i=0; alln++; } return(1); } Shot: %d Lev:%d",alln,shot,level); TextOut(hdc,10,10,szBuffer,strlen(szBuffer)); 试一试 更改一些源代码,看看能有什么效果。