使用directX 7结合C#进行2D游戏编程
使用directX 7結(jié)合C#進(jìn)行2D游戲編程
前言
對于C#的開發(fā)人員來講,GDI+ 是一個擁有豐富的繪圖API指令、傳統(tǒng)、高效的程序集。但不幸的是,你要想用她來開發(fā)一個復(fù)雜而又平滑的動畫的時候,我們會發(fā)現(xiàn)GDI+只能做到有限的快。因此,它是絕不適合做游戲開發(fā);不要妄想你那飛快的處理器和嶄新的、長著奇異形狀的圖形卡,到DirectX API來。
不幸的是,.net和C#并非DirectX的官方開發(fā)平臺,但是DirectX 9可利用.net平臺做為其標(biāo)準(zhǔn)開發(fā)平臺,我們只需引用他的命令空間就可以了。不過我們要以利用VB7、8的DirectX組件在C#中進(jìn)行開發(fā)。本文將利用一個簡單的突圍風(fēng)格的游戲(我突發(fā)奇想的叫她做"太空突圍")來示范在C#環(huán)境下,如何利用VB的DirectX的組件進(jìn)行開發(fā)。
DirectX 和 DirectDraw
DirectX 8 之前,DirectDraw是DirectX的主要2D接口。自從windows主流的游戲編程偏離平面游戲時,Mircrosoft決定將2D和3D的API原理合并,新的接口稱為DirectGraphics。這樣做非常有好處,因?yàn)槿绻阆腴_發(fā)純2D的游戲,哪他將沒有任何3D的加速,這樣總有些不好吧,大大的不好:-
l DirectGraphics需要一張3D加速卡做為2D的硬件加速
l DirectGraphics可直接繪制2D圖形。DirectDraw則需要了解一些3D的概念
所以當(dāng)開發(fā)純2D游戲時依然可以首要考慮DirectDraw,在DirectX 8下依然可以建立DirectX 7(提供DirectDraw的版本)的對象。
設(shè)置DirectX程序
進(jìn)行.net的DirectX開發(fā),首先引用DirectX的COM dll文件。如何加入引用?在"項(xiàng)目"菜單中選擇"添加引用",選擇"COM",如果你已經(jīng)安裝了DirectX 7、8,你就能在"組件名稱"中找到"DirectX 7 for Visual Basice Type Library"或"DirectX 8 for Visual Basice Type Library"。"選擇"他們。DirectX程序在.net中必須基于winForm程序,所以,下一步要建立一個基本的無邊框的winForm。
初始化DirectX
在《太空突圍》的主DirectX對象及他們的初始化封裝在GameDirectDrawClass類中。DirectDraw有兩種顯示模式:全屏和窗口模式。在DirectDraw的游戲開發(fā)中,全屏模式是最常用的,他可在游戲的全程獨(dú)占屏幕作為用戶的界面,他對故事的演繹、用戶的投入程度,都要好優(yōu)于windows模式。以下變量是GameDirectDrawClass類用于初始化全屏模式的(全文我都假定你已經(jīng)在文件的頭部加入了"using DxVBLib;"的語句)。
private DirectX7 m_objDirectX = new DirectX7();
private DirectDraw7 m_objDirectDraw;
private DirectDrawSurface7 m_objPrimarySurface;
private DirectDrawSurface7 m_objBackBufferSurface;
private DDSURFACEDESC2 m_objPrimarySurfaceDescription;
private DDSURFACEDESC2 m_objBackBufferSurfaceDescription;
變量m_objDirectX是游戲DirectX主對象的一個實(shí)例,另預(yù)先準(zhǔn)備m_objDirectDraw是游戲主DirectDraw對象的一個實(shí)例。另兩年變量(m_objPrimarySurface 和 m_objBackBufferSurface)是DirectDraw的Surface,所謂Surface就是代表我們實(shí)際作圖的平面、紙張,就象GDI+的圖形對象一般。
每個DirectDraw 程序都必須有最少一個Surface對象。Surface指向的是物理顯存。經(jīng)常的做法是建立一個主surface對象,這里是m_objPrimarySurface變量。除主surface對象之外,應(yīng)有一些不顯示的surface存在于內(nèi)存中。作為第二種surface變量我們通常稱為后緩存(m_objBackBufferSurface)。
后緩存surface在程序中是作為雙重緩沖。雙重緩沖的過程是這樣的:我們在第二個surface中進(jìn)行的一個幀的所有的繪圖(譯者:我們應(yīng)有一個概念:每個surface就是動畫中的其中一幀),當(dāng)所有繪圖動作完成后就可以將整個緩沖區(qū)拷貝到主surface。DirectDraw全屏下進(jìn)行這種整頁的拷貝工作稱為page flipping(譯者:我也喜歡將其譯為"頁翻轉(zhuǎn)")。當(dāng)頁翻轉(zhuǎn)時,主surface將指向BackBufferSurface的內(nèi)存地址,而BackBuffer將指向主surface原指向的地址。這樣一來,主surface包含Backbuffer的內(nèi)容,BackBuffer對象也包含著主surface的內(nèi)容。一次頁翻轉(zhuǎn)后,BackBuffer就會清掉緩存的內(nèi)容,并進(jìn)行下一幀的繪圖工作。圖2說明了這個過程。
這剩下的兩個變量m_objPrimarySurfaceDescription、m_objBackBufferSurfaceDescription是用來設(shè)置一些道具的surface,將在下面詳述。
InitialiseDirectXFullScreen()方法是GameDirectDraw類的用于初始化DirectDraw對象的。他有一個整形的參數(shù),指向一個表單的句柄(handle)。代碼如下:
InitialiseDirectXFullScreen(int objDisplayFormHandle)
{
m_objDirectDraw = m_objDirectX.DirectDrawCreate("");
m_objDirectDraw.SetCooperativeLevel (objDisplayFormHandle, CONST_DDSCLFLAGS.DDSCL_FULLSCREEN | CONST_DDSCLFLAGS.DDSCL_EXCLUSIVE);
m_objDirectDraw.SetDisplayMode(640, 480, 16, 0, CONST_DDSDMFLAGS.DDSDM_DEFAULT);
m_objPrimarySurfaceDescription.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS | CONST_DDSURFACEDESCFLAGS.DDSD_BACKBUFFERCOUNT;
m_objPrimarySurfaceDescription.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE |CONST_DDSURFACECAPSFLAGS.DDSCAPS_FLIP | CONST_DDSURFACECAPSFLAGS.DDSCAPS_COMPLEX;
m_objPrimarySurfaceDescription.lBackBufferCount = 1;
m_objPrimarySurface = m_objDirectDraw.CreateSurface(ref m_objPrimarySurfaceDescription);
DDSCAPS2 ddscaps = new DDSCAPS2();
ddscaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_BACKBUFFER;
m_objBackBufferSurfaceDescription = m_objPrimarySurface.GetAttachedSurface(ref ddscaps);
m_objBackBufferSurfaceDescription(ref m_objBackBufferSurfaceDescription);
}
在代碼的第一行,建立了一個DirectX 7的對象。這DirectDraw對象調(diào)用了一次SetCooperativelevel()方法,設(shè)置DirectDraw對象與操作系統(tǒng)聯(lián)合(co-operation)的水平。第一個參數(shù)是程序要用的form的句柄,第二個參數(shù)包含著一些標(biāo)記(flags),指示程序所需的聯(lián)合水平。這里我們用了兩個標(biāo)記,我們既要全屏又要獨(dú)占顯示控制。
下一個DirectDraw方法是SetDisplayMode()。他是用于設(shè)置屏幕屬性,頭兩個參數(shù)指定分辨率為640*480,第三個指定為16Bit色,第四個是刷新率(這里設(shè)為0,DirectDraw將自動使用最好的分辨率)第五個指定沒有高級分辨率使用(no advanced resolutions are to be used不明白)。
跟著的是對主surface 的描述變量(descriptor)的賦值,這變量將用來建立主surface。我們指定的這些標(biāo)記將用來指定surface的容量和他的緩沖數(shù),利用的是lflags的屬性。下一行定義了surface的能力。頭一變量指定了這將要是一個主surface,跟著的變量指定我們將要使用"頁翻轉(zhuǎn)",這最后的變量是我們使用"頁翻轉(zhuǎn)"而特定需要的。下一行定義了surface的緩沖數(shù),這里指定了一個。定義設(shè)好后,我們利用DirectDraw對象的CreateSurface()方法建立主surface,該方法需要一個指向"描述變量"的參數(shù)。
當(dāng)主surface建立后,BackBuffer也能建立了。我們設(shè)置相同的屬性給BackBuffer的描述變量,并指定為一個后緩沖surface,于是我們就用主surface對象的GetAttachedSurface()方法建立這個BackBuffer。
顯示位圖
在DirectDraw中,位圖必須加載到新的surface然后拷貝到BackBuffer。在游戲中,許多位圖繪制代碼都封裝在抽象類BitmapObject中,所有游戲?qū)ο蠖祭^承自該抽象類。主變量使用BitmapObject類來建立位圖對象,并把位圖繪制在Backbuffer。
public const int BLACK_TRANSPARANT_SPRITE = 1;
public const int NORMAL_BITMAP = 0;
protected DDSURFACEDESC2 m_objDDSurfaceDescription;
private DirectDrawSurface7 m_objBitmapSurface;
protected RECT m_objSizeRECT;
前兩行定義的兩個常數(shù)用以區(qū)分對象是組圖(sprite)還是位圖。組圖是指一些不規(guī)則的小圖。另,m_objDDSurfaceDescription是一個surface的描述對象,用以為設(shè)置surface對象屬性服務(wù),m_objBitmapSurface是一個DirectDraw的surface對象,他代表著一個位圖。剩下變量是一個RECT結(jié)構(gòu),是個矩形結(jié)構(gòu),他代表著surface的方形區(qū)域,surface用于拷貝緩沖區(qū)信息。
InitialiseSurfaceDescription(int intBitmapWidth, int intBitmapHeight) {
m_objDDSurfaceDescription.lFlags = CONST_DDSURFACEDESCFLAGS.DDSD_CAPS | CONST_DDSURFACEDESCFLAGS.DDSD_WIDTH | CONST_DDSURFACEDESCFLAGS.DDSD_HEIGHT;
m_objDDSurfaceDescription.ddsCaps.lCaps = CONST_DDSURFACECAPSFLAGS.DDSCAPS_OFFSCREENPLAIN;
m_objDDSurfaceDescription.lWidth = intBitmapWidth;
m_objDDSurfaceDescription.lHeight = intBitmapHeight;
m_objSizeRECT.Bottom = intBitmapHeight;
m_objSizeRECT.Right = intBitmapWidth;
}
方法的第一行代碼設(shè)置surface的描述對象的lFlags屬性,他指定的性質(zhì)將用于設(shè)置surface的屬性、寬、高。跟著的代碼設(shè)置了另surface的性質(zhì),這surface是非顯示surface。一個非顯示surface是指存在于內(nèi)存中,而自身不顯示給用戶。接著的兩行設(shè)置了surface的寬、高。最后兩行設(shè)置一個RECT結(jié)構(gòu)的寬、高。
每次surface的建立都要進(jìn)行surface描述對象的設(shè)置,我們將這些代碼放在了InitialiseSurface()方法中。這方法有三個參數(shù),程序的DirectDraw對象、一個指向一個位圖的字符串、一個整數(shù)(指針)指向?qū)⒃诒唤⒌奈粓D、組圖。方法代碼如下:
InitialiseSurface(DirectDraw7 DirectDraw, string strBackgroundBitmap, int intBitmapType)
{
try
{
m_objBitmapSurface = DirectDraw.CreateSurfaceFromFile( strBackgroundBitmap,
ref m_objDDSurfaceDescription );
}
catch ( Exception e)
{
System.Windows.Forms.MessageBox.Show( "Unexpected exception: " + e.ToString(), "Unexpected Exception" );
System.Windows.Forms.Application.Exit();
}
switch (intBitmapType)
{
case BitmapObject.BLACK_TRANSPARANT_SPRITE:
DDCOLORKEY objBlackKey;
objBlackKey.low = 0; objBlackKey.high = 0;
m_objBitmapSurface.SetColorKey( CONST_DDCKEYFLAGS.DDCKEY_SRCBLT, ref objBlackKey);
break;
}
}
前一部分代碼是利用一個位圖文件來建立surface對象,他使用了DirectDraw對象的CreateSurfaceFromFile()方法。CreateSurfaceFromFile()有兩個參數(shù),一個是文件的字符串,另一個是需處理的surface的描述對象。
后一部分代碼用于建立組圖(sprite)。我早前說過,組圖是不規(guī)則的一此小圖,不幸的是,位圖文件只能是方形的,所以DirectDraw只有將方形的圖形轉(zhuǎn)變成組圖。過程是這樣的:首先為surface定義一個顏色值,當(dāng)surface裝載到另一個surface時,DirectDraw將位圖的什么該值顏色的位置換為透明。這游戲所有組圖都用黑色值,第一行代碼建立一個DirectDraw顏色對象,下兩行定義了黑色中最高、最低值。接著調(diào)用位圖surface對象的SetColorKey()。
DDCKEY_SRCBLT:?
Color key or color space to be used as a source color key for blit operations.?
source color key:
A color that (in the case of blitting) is not copied to, or (in the case of overlays) not visible on, the destination。
destination color key:
The color that (in the case of blitting) is replaced or (in the case of overlays) is covered on the destination surface.
位圖surface建立后,就可加載到BackBuffer中,這種由一surface信息覆蓋到另一surface的過程我們稱之為"blitting"---"bit block transfer"(我稱其為"字組轉(zhuǎn)移")。為了字組轉(zhuǎn)移我們定義BltFast()方法,以下是BltFast()的代碼,用于從BitmapObject類轉(zhuǎn)移組圖到Backbuffer。
objBackBufferSurface.BltFast( this.XPosition, this.YPosition, m_objBitmapSurface, ref m_objSizeRECT, CONST_DDBLTFASTFLAGS.DDBLTFAST_SRCCOLORKEY | CONST_DDBLTFASTFLAGS.DDBLTFAST_WAIT );
第一個參數(shù)指出組圖將要放的點(diǎn)距BackBuffer左邊的點(diǎn)值,第二個參數(shù)是該點(diǎn)距Backbuffer頂邊的點(diǎn)值;第三個參數(shù)是組圖對象,第四個是定義了轉(zhuǎn)移的區(qū)域大小的RECT結(jié)構(gòu),最后一個參數(shù)是轉(zhuǎn)移的標(biāo)志,這里所用的兩個標(biāo)志指明了我們要使用指定對象顏色值和DirectDraw必須要等待方法完成轉(zhuǎn)換后才進(jìn)行下一步的工作。
翻轉(zhuǎn)BackBuffer到主surface
一個幀的所有位圖轉(zhuǎn)換完成后,BackBuffer就需要將其自身翻轉(zhuǎn)到主surface。這項(xiàng)工作由GameDirectDraw類的FlopBackBufferAndPrimary()方法完成。該方法只有一行代碼。
this.PrimarySurface.Flip(this.BackBufferSurface, CONST_DDFLIPFLAGS.DDFLIP_WAIT);
正如我們所看到的,主surface對象的Flip()方法被調(diào)用,他需要兩年參數(shù)。第一個是BackBuffer對象,第二個要求DirectDraw等待翻轉(zhuǎn)的完成。一次翻轉(zhuǎn)完成,BackBuffer就會清除自身內(nèi)容并進(jìn)行下一個動畫的轉(zhuǎn)移。
Conclusion
This article has detailed the core elements of building a game using DirectX and DirectDraw. DirectX is a huge topic but it is hoped that in conjunction with the source code for the Space Breakout game youll have all you need to begin building your own 2D DirectX games.
譯:
結(jié)論
本文詳述了DirectX和DirectDraw建立一個游戲的主要原理。DirectX是一個龐大的話題,但我希望大家認(rèn)真研究"空間突圍"的代碼,你將會學(xué)會開發(fā)DirectX 2D游戲所需要的知識。
http://www.cnblogs.com/ww21xx/articles/93740.html
總結(jié)
以上是生活随笔為你收集整理的使用directX 7结合C#进行2D游戏编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JM8.5中的7种宏块模式问题 - zh
- 下一篇: 错误检测dP-bitstream-ei_