天天看點

2D遊戲程式設計筆記-4

本人同意他人對我的文章引用,但請在引用時注明出處,謝謝.作者:蔣志強

對Windows平台來說,位圖是一種非常特殊的圖像格式,位圖是windows作業系統直接從底層所支援的圖像格式。位圖分為DIB(裝置無關位圖)和DDB(裝置相關位圖兩類),這兩種位圖彼此是有關系的,DIB和DDB之間是可以互相轉換的。DDB(即裝置相關位圖)是windows的GDI對象的一種,他所表示的圖像與具體的顯示圖像的系統相關,也就是說一樣的DDB在不同的顯示裝置上顯示的效果可能是不一樣的,是以DDB是不用于存儲的。我們常見的以檔案格式儲存的位圖,也就是那些以bmp或dip作為字尾名的檔案是裝置無關位圖。DIB之是以稱為裝置無關位圖,就是因為它記錄了圖像的所有資訊,在不同的裝置上顯示都會是一樣的。

在具體的程式設計中,我們有時需要将以檔案格式(bmp或dip為字尾名的檔案)的位圖在程式運作過程中,進行載入并使用載入的位圖。在這個時候,從DIB到DDB的轉換就發生了。在windows平台下,我們必須使用HBITMAP這種被稱為位圖句柄的變量來進行引用和操作GDI位圖對象,HBITMAP類型變量所引用的位圖就是DDB,它與具體的顯示裝置相關,在具體需要顯示或操作的時候DDB産生。我們可以使用LoadImage函數從檔案中裝載DIB,該函數傳回DDB位圖的句柄,從DIB到DDB的轉換在調用該函數時發生。這個轉換過程不用我們操心,LoadBitmap函數傳回的也是DDB位圖的句柄。如果你還沒有搞明白DIB和DDB的差別,你可以參考《windows程式設計》的相應章節。我們要在程式中使用位圖有兩種方式:1從BMP檔案中加載;2從程式的資源中加載(如果你還不太了解程式資源的相關概念,請參考《windows程式設計》的第十章)。

LoadImage函數可以從指定目錄加載位圖檔案,傳回DDB位圖句柄;該函數也可以從程式資源中加載位圖傳回DDB位圖句柄,LoadBitmap隻能從程式資源中加載位圖傳回DDB位圖句柄。下面的代碼将程式資源中的位圖加載,把傳回的DDB句柄賦給了一個HBITMAP變量:

  if((bitmap = LoadBitmap(GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_NPC))) == NULL)

   return FALSE;

下面的代碼将指定位圖檔案(顔色選擇32.bmp)加載到程式中,并把傳回的DDB句柄賦給了一個HBITMAP變量:

if((bitmap = (HBITMAP)LoadImage(NULL,TEXT("test//顔色選擇32.bmp"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE)) == NULL) 

   return FALSE;

具體函數各個參數的意義,請查閱MSDN文檔說明。當我們将位圖轉載以後(無論你是從檔案中裝載還是從程式的資源中裝載),也就是我們獲得一個DDB句柄以後,我們就可以做下面的事情了:将該位圖放到我們離屏頁面中去,下面的代碼完成這樣的工作:

 BITMAP bitmapInfor;

 GetObject(bitmap,sizeof(BITMAP),&bitmapInfor);

  if((p_PicResourceSurface->GetDC(&hdc)) != DD_OK)

   return FALSE;

HDC compataleDC = CreateCompatibleDC(hdc);

 SelectObject(compataleDC,bitmap);

 DDCOLORKEY picColorKey;

 picColorKey.dwColorSpaceLowValue = picColorKey.dwColorSpaceHighValue = RGB(255,0,255);

 if((p_PicResourceSurface->SetColorKey(DDCKEY_SRCBLT ,&picColorKey)) != DD_OK)

   return FALSE;

 BitBlt(hdc,0,0,bitmapInfor.bmWidth,bitmapInfor.bmHeight,compataleDC,0,0,SRCCOPY);

 p_PicResourceSurface->ReleaseDC(hdc);

上面的代碼中的BITMAP是一個用于描述DDB位圖屬性的結構體,GetObject函數根據bitmap這個我們在上面載入的DDB位圖的屬性填充該結構體。GetDC是IDirectDrawSurface接口中的方法,用于獲得頁面的DC,要注意的是該方法内部調用了Lock方法,将該頁面記憶體區域鎖定,在鎖定期間從鎖定頁面往其他地方Blit将失效(剛才我就是由于這個原因程式老是不能正常運作,大家要注意)。然後我們建立一個與從離屏頁面所得到的DC相相容的DC,并将得到的DDB位圖bitmap選入該相容DC中。然後我們使用GDI的BitBlt函數,将相容DC中的内容傳送到離屏頁面的DC中,這樣就完成了将DDB位圖裝入離屏頁面的操作。要特别注意,一定要使用ReleaseDC釋放,我們用GetDC所得到的離屏頁面的DC,因為在GetDC時,頁面将會被鎖定,調用ReleaseDC将對所鎖定的頁面解鎖。

你肯定會注意到上面SetColorKey的代碼,這是設定頁面的關鍵色。因為圖檔資源都是矩形的,但是我們在程式中往往不想顯示整個矩形的内容方框,而隻是顯示矩形圖檔中踢出背景顔色後的内容。這個時候我們設定頁面的關鍵色,然後從該頁面往其他頁面(比如背景頁面)進行圖像Blit的時候,就可以指定關鍵色不進行傳送。關鍵色可以不隻一種(雖然我們平時一般都隻指定一種關鍵色),在關鍵色DDCOLORKEY結構體的LowValue和HighValue之間的所有顔色都是關鍵色(RGB宏将顔色轉換為一個整型數值)

現在我們可以用BitBlt函數完成将相容DC中的内容傳送到首頁面DC中,在首頁面的内容就會馬上顯示在螢幕上.很令人興奮吧,忙了半天,終于在螢幕上顯示出内容了!

上面将圖像裝載到首頁面的方法對背景頁面同樣适用,操作代碼完全是一樣的,我就不在重複了.當背景頁面裝載圖像後,通過換頁操作,首頁面與背景頁面交換,以前的首頁面變成現在背景頁面,以前的背景頁面變成現在的首頁面,這樣背景頁面上的内容就變成首頁面内容顯示在了螢幕上了.

當使用上面的方法把圖檔裝載到頁面後,就可以先在背景頁面把繪圖操作完成以後在進行頁面的Flip,使用Flip函數将使以前的首頁面變為背景頁面,以前的背景頁面變為目前的首頁面,因為首頁面上面的内容将會直接顯示到螢幕上,這樣之前在背景頁面繪制的内容将在螢幕上顯示出來。而且由于繪圖是在背景頁面上操作的,是以繪圖的中間過程不會顯示出來,程式運作時,也就不會有閃爍現象了。該函數的原型如下:

HRESULT Flip(

  LPDIRECTDRAWSURFACE7 lpDDSurfaceTargetOverride, 

  DWORD dwFlags                                   

);

在代碼中直接使用p_FrontSurface->Flip(NULL,0),就可以實作上面的操作了。我們需要注意的是,DDraw程式獨占顯示裝置時,如果跳出該程式,比如按下alt+tab切換到其它程式時,或者最小化目前Ddraw程式時,DDraw程式将失去對顯示裝置的獨占,是以這個時候Flip操作肯定會出丢失頁面的錯,丢失頁面後,以前頁面中裝載的圖象都會丢失需要重新裝入,是以我們一定要處理這個情況。我們可以在代碼中這樣進行處理:

HRESULT ddrval;

ddrval=lpDDSPrimary->Flip(NULL,DDFLIP_WAIT);

if (ddrval==DDERR_SURFACELOST)

{

lpDD->RestoreAllSurfaces( );

ReloadResourceImages( );  //自定義的函數,将資源圖檔裝載到頁面中

}

這次筆記至此講解了Ddraw程式設計的最基礎的知識,在後續的筆記中我将實作一個DDraw的俄羅斯方塊的遊戲。很吸引人吧,下次再見哦^_^

本文來自CSDN部落格,轉載請标明出處:http://blog.csdn.net/gamer_gerald/archive/2006/09/02/1160905.aspx

繼續閱讀