日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

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

發布時間:2024/1/17 c/c++ 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Visual C++】游戏开发笔记之八——基础动画显示(二)游戏循环的使用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

筆記七中我們講解了用定時器來產生動畫的效果。定時器的使用固然簡單方便,但是事實上這樣的方法僅適合用在顯示簡易動畫及小型的游戲程序中。因為一般而言,游戲本身需要顯示順暢的游戲畫面,使玩家感覺不到延遲的狀態。基本游戲畫面必須在一秒鐘之內更新至少25次以上,這一秒鐘內程序還必須進行消息的處理和大量數學運算甚至音效的輸出等操作。而使用定時器的消息來驅動這些操作,往往達不到所要求的標準,不然就會產生畫面顯示不順暢和游戲響應時間太長的情況。

?

這里我們提出一種游戲循環的概念,游戲循環是將原先程序中的消息循環加以修改,方法是判斷其中的內容目前是否有要處理的消息,如果有則進行處理,否則按照設定的時間間隔來重繪畫面。下面是接下來一段游戲循環的程序代碼:

?

//游戲循環 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次剛好可以達到期望值。

由于循環的運行速度遠比定時器發出時間信號來得快,因此使用游戲循環可以更精準地控制程序運行速度并提高每秒鐘畫面重繪的次數。

?

?

?

了解了游戲循環使用的基本概念之后,接下來的范例將以游戲循環的方法進行窗口的連續貼圖,更精確地制作游戲動畫效果。

?

?

#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; }GetMessage(&msg,NULL,NULL,NULL); //感謝xiaoxiangp的提醒,需要在進入消息循環之前初始化msg,避免了死循環發生的可能性。 //游戲循環 while( msg.message!=WM_QUIT ) { if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } else { tNow = GetTickCount(); if(tNow-tPre >= 100) //當此次循環運行與上次繪圖時間相差0.1秒時再進行重繪操作 MyPaint(hdc); } } return msg.wParam; } //****設計一個窗口類,類似填空題,使用窗口結構體************************* ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = NULL; wcex.hCursor = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = "canvas"; wcex.hIconSm = NULL; return RegisterClassEx(&wcex); } //****初始化函數************************************* // 從文件加載位圖 BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { char filename[20] = ""; int i; hInst = hInstance; hWnd = CreateWindow("canvas", "動畫演示" , 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); //載入各個人物位圖 for(i=0;i<7;i++) { sprintf(filename,"man%d.bmp",i); man[i] = (HBITMAP)LoadImage (NULL,filename,IMAGE_BITMAP,640,480,LR_LOADFROMFILE); } num = 0; frame = 0; MyPaint(hdc); return TRUE; } //****自定義繪圖函數********************************* // 1.計算與顯示每秒畫面更新次數 // 2.按照圖號順序進行窗口貼圖 void MyPaint(HDC hdc) { char str[40] = ""; if(num == 7) num = 0; frame++; //畫面更新次數加1 if(tNow - tCheck >= 1000) //判斷此次繪圖時間由前一秒算起是否已經達到1秒鐘的時間間隔。若是,則將目前的'frame'值賦給"fps",表示這一秒內所更新的畫面次數,然后將“frame”值回0,并重設下次計算每秒畫面數的起始時間"iCheck"。 { fps = frame; frame = 0; tCheck = tNow; } SelectObject(mdc,man[num]); //選用要更新的圖案到mdc中,再輸出顯示每秒畫面更新次數的字符串到mdc上,最后將mdc的內容貼到窗口中。 sprintf(str,"每秒顯示 %d個畫面",fps); TextOut(mdc,0,0,str,strlen(str)); BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY); tPre = GetTickCount(); //記錄此次繪圖時間,供下次游戲循環中判斷是否已經達到畫面更新操作設定的時間間隔。 num++; } //******消息處理函數********************************* LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int i; switch (message) { case WM_DESTROY: //窗口結束消息 DeleteDC(mdc); for(i=0;i<7;i++) DeleteObject(man[i]); ReleaseDC(hWnd,hdc); PostQuitMessage(0); break; default: //其他消息 return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }

?

?

?

程序的運行結果如下圖:


?

當然想要得到上述動畫,我們需要把幾幅位圖文件放到工程文件夾下。

?

這個范例中我們設定的畫面更新時間間隔為0.1秒,所以每秒鐘最多會更新10次畫面。不過如果在運行這個例子的時候同時也運行其他的程序,那么CPU必須馬上出去處理所開啟的其他程序,因此可能會使得每秒畫面的更新次數稍稍下降。

?

?


?

筆記八到這里就結束了。

?

本節源代碼請點擊這里下載:【Visual C++】Code_Note_8

?

請大家繼續關注【Visual C++】游戲開發筆記系列。

非常希望能與大家一起交流,共同學習和進步。

最后,謝謝大家的支持~~~

?

The?end

?

轉載于:https://www.cnblogs.com/dyllove98/archive/2012/03/15/2461882.html

總結

以上是生活随笔為你收集整理的【Visual C++】游戏开发笔记之八——基础动画显示(二)游戏循环的使用的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。