遊戲編輯器框架教程 (轉)

gugu99發表於2008-03-27
遊戲編輯器框架教程 (轉)[@more@]

-------------------------------------------------------
遊戲編輯器教程
無心柳
-------------------------------------------------------

一、前言:

我一直在尋找DX和MFC類庫的結合點,前段時間曾經在第二人生http//king.com.cn/secondlife上放了一個從《程式設計技巧與雜誌》來的例子。應該說,那個例子非常不錯,唯一的缺點就是它只研究了全螢幕顯示的情況,而對於地圖編輯器人員來說,迫切需要的是既能夠完全使用原有MFC的框架又能夠使用DX的功能的東西,這也是我一直在尋找的,今天(1999/12/4)總算找到了。

促使我找到這個辦法的是為MUD編寫的那個地圖編輯器,雖然功能上沒有什麼欠缺,但誠如美工所言,介面太差了,按鈕按下去的時候沒有一個響應動作,而且也不方便使用MFC的全部功能。在完成這個地圖編輯器以後,其他員的MFC編輯器也在趕製之中,而他們的圖形顯示部分是一個難題。如果要使用經典程式設計方法去操作和顯示256色以上的圖片,在程式上是非常麻煩的。能否將MFC與DDRAW的視窗完美地融合?在完成地圖編輯器以後,我已經有了這樣的設想,就等著拿到機器上去測試了。結果一試之下,完全可行,而且它是如此地簡單!

二、第一個例子:

在這個例子中,我用VC的AppWizard生成了一個標準的單文件視窗並儲存。然後,在視類CGameEditView的頭中加入了四個DX成員,一個DDRAW指標,一個DDRAW4指標,一個前緩衝,一個後緩衝,具體可以看原始碼。在標頭檔案中,另外加入了兩個,一個是Msg函式,用於顯示訊息框,這是從別人的例子中直接複製過來的;另一個是InitDDrawSurface()函式。然後在CGameEditView.cpp里加入了這兩個函式的函式體。Msg沒什麼說的,你直接複製上去用就行了。InitDDrawSurface你也可以直接複製,這個函式里建立了一個DDRAW,再利用它獲取了DDRAW4的介面。然後用DDRAW4介面建立一個DDSURFACE4主螢幕緩衝頁,它負責在螢幕上顯示內容。最後建立一個DDSURFACE4的後臺緩衝頁,它負責在主緩衝在螢幕上顯示之前在後臺準備一下畫面。僅此兩個函式而已。

程式中有兩個動作,一個是在預建立視窗時InitDDrawSurface()對DDRAW頁面進行初始化,如果不成功程式就退出。另一個動作就是在視類的OnDraw()中將一塊矩形區域從後臺緩衝複製到前緩衝(也就是在螢幕上顯示出來)。由於後臺緩衝沒有放入資料,所以顯示的內容將是隨機的,一般是黑色的。顯示的步驟可以看原始碼上的程式註釋,我一般寫得比較細。

為什麼不加入什麼撞球等的變化動作?這是因為我只想告訴大家一個最簡單的DDRAW視窗頁面如何建立和使用,下面的教程中會慢慢加入如何讀入點陣圖塊和顯示,時間控制,視窗區域檢測,剪下塊,顏色鍵等內容。當教程結束的時候,用MFC和DDRAW做一個簡單遊戲應該沒有問題了。

原始碼

三、第二個例子:

1、上個例子中有個明顯的,在InitDDrawSurface()中建立後臺緩衝的時候,顯式地指定了寬和高。在前緩衝lpMainSurface建立時,沒有指定大小,因為不需要,前緩衝指的就是整個螢幕的範圍,它使用的是顯示。而後緩衝是不顯示的內容,它實際是在記憶體中(視窗模式不能在顯示記憶體中再建立後臺頁面)建立的一個頁面,一般情況下,應該設定得和前緩衝一樣大或者更大。1024*768的顯式指定對一般顯示器可能夠了,但萬一使用更大的解析度就可能導致錯誤。所以第二個例子中首先修改了InitDDrawSurface()中建立後臺緩衝的部分,用標準函式GetDeivceCaps獲取了當前顯示分辯率的高和寬(當然也可以獲得顏色位數,原始碼中有)。然後用獲取的高和寬來建立後臺緩衝,這樣就保證了與解析度的大小相同。當然這也不是絕對保險,萬一使用者執行中修改了解析度仍有可能導致錯誤,但一般我們不需要為那種情況負責了,可以不去考慮。

2、這次我們要讀入一個圖片,看起來挺恐怖,你好象需要去研究BITMAP的檔案結構。其實不需要那麼複雜,對一般的遊戲和編輯器來說,根本不用去了解那些細節的問題,在DX的例程中多次用到的兩個檔案可以直接搬過來用,它們是ddutil.h和ddutil.cpp,你可以在大部分DX的例程中找到它們,然後複製到你程式的資料夾下,再在工程中加入這兩個檔案,試試重編譯。直接重編譯是無法成功的,這是因為MFC程式有點特殊性,要使它能被MFC所用,必須在上面提到的這兩個檔案首部都追加一句#include "stdafx.h"。用過這個語句,MFC就認這兩個檔案,然後可以正常編譯透過。當然,如果你想在VIEW類中使用裡的函式,還要在GameEditView.cpp的頭部加入#include "ddutil.h"。這是常識,說這些好象有點多餘,在原始碼中這幾個步驟都做了而且有說明。

3、透過第2步,已經可以隨時讀入BMP檔案了,具體的讀法是非常簡單的,因為你已經可以使用ddutil.cpp裡的函式。如果需要,你也可以去修改這個檔案的原始碼或者製作修改版。作為例子,我先在GameEditView.h中增加了一個DDSURFACE4的頁面指標:

LPDIRECTDRAWSURFACE4 lpBitMapBuffer;//DirectDraw讀入的點陣圖頁面儲存在這裡

再在GameEditView.cpp的預建立視窗PreCreateWindow()函式中將一幅點陣圖讀入這個點陣圖頁面。讀入成功後,將這個臨時頁面的內容複製到後臺緩衝。這樣,後臺緩衝就有了內容。再編譯一次程式,會發現原來視窗左上角那個黑塊已經變成這幅圖片(一幅UO中截下來的騎馬圖),程式碼如下:

lpBitMapBuffer=DDLoaitmap(lpDD4,"test.bmp",200,200);
if(NULL==lpBitMapBuffer)//如果沒有讀入成功,退出程式
{
Msg("無法裝入點陣圖,演示無法進行");
exit(-2);
}
//讀入成功就複製到後臺緩衝去
lpBackBuffer->BltFast(0,0,lpBitMapBuffer,&(CRect(0,0,200,200)),FALSE);

你可以看到程式碼中指定的位件名是test.bmp,所以你也需要一個這樣檔名的點陣圖檔案,在下面的原始碼包裡附有一個,如果你想換一個檔案也可以,不過這個檔案以後將用於演示動畫的例子。

第二個例子完,需要的話請下載原始碼

三、與GDI結合:

上面的兩個例子的原始碼中沒有包含資原始檔,所以在使用的時候請先按照上面提到的方法建立自己的簡單MFC單文件程式,再將原始碼檔案替換你自己的檔案再編譯。

在第二個例子中,讀入了一幅點陣圖並顯示在視窗的左上角。這在程式執行中沒有任何問題,而且速度還相當快。但如果你同時執行了其他程式,或者將視窗移動到螢幕的邊緣位置,會出現一些不正常現象。如果將視窗移動到螢幕邊緣,在從後臺到前臺進行傳送的時候,會發生非常矩形錯誤,意思是指你試圖將頁面傳送到螢幕區域外,也就是前緩衝以外(前面說過,前緩衝與螢幕大小是一樣的)。其結果並不會使你的程式當機,只是這次傳送不會進行。另外,當你用其他程式的視窗蓋住本程式視窗並移動上面的視窗的時候,本視窗的重新整理可能導致將點陣圖蓋在其他視窗區域內。這是個嚴重的問題,在編寫全螢幕程式的時候不會發生這種情況,因為螢幕被你的程式獨佔了,而在編寫視窗程式的時候,你的程式就會顯示非常差勁。

要解決上面的問題,一個辦法是當程式失去焦點的時候,你就禁止將點陣圖從後緩衝傳送到前緩衝,當重新獲得焦點的時候,再恢復點陣圖傳送。但有時候這樣不理想,比如你在進行程式或者遊戲的時候,同時發ICQ的資訊,雖然ICQ佔的螢幕面積不大,還是會導致你的程式停止畫面,而如果你在遊戲中此時正在緊張而且隨時需要你干預的話,程式看起來就非常不友好。

另一個辦法是與GDI結合,與GID結合會導致在影像速度上有微小的下降,但會使你的程式看來非常自然。其實方法也非常簡單,就是獲取後臺緩衝的HDC,然後用HDC的BitBlt方法將後臺緩衝複製給視窗CDC,可以將OnDraw中的BltFast的方法修改為:

HDC hdc;

lpBackBuffer->GetDC(&hdc);//獲得後臺緩衝的HDC

::BitBlt(pDC->m_hDC,0,0,100,100,hdc,0,0,SRCCOPY);//將後臺緩衝的圖片傳送到視窗DC

lpBackBuffer->ReleaseDC(hdc);//不要忘了用完後釋放HDC,否則會出錯

為了與HDC匹配,所以使用pDC的成員m_hDC。BitBlt的具體用法可以看一下幫助檔案。使用這個辦法以後,無論你將視窗移動到什麼位置,以及無論你用什麼視窗蓋住程式的視窗,都不會有任何不正常的現象發生。它唯一的缺點就是比BltFast慢一點點。因為DC的處理方法是分幾次進行,第一次複製到一個DC自己的後臺緩衝,然後根據視窗的合法區域分一次或多次複製到螢幕。所以這個方法適用於製作編輯器以及對速度不是極度敏感的遊戲。如果要達到最高速度,當然是非全螢幕模式莫屬。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1001539/,如需轉載,請註明出處,否則將追究法律責任。

相關文章