程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> 關於C# >> DirectDraw之C#入門攻略

DirectDraw之C#入門攻略

編輯:關於C#

DirectX簡述

DirectX本身為游戲開發的一套SDK,其本身原來僅僅是用來與OpenGL,3DFX競爭的一套用於視頻游戲開發的SDK.。現在Microsoft已經發布其8.1版本。到DirectX7為止DirectX已經成為一套功能齊全的多媒體開發SDK.。由於其易用(相對於GDI API)高效也就成為了視頻播放,3D繪圖等高質量多媒體程序(high-performance multimedia applications)的良好開發平台。由於Microsoft在軟件業的霸主地位,使得DirectX得到了眾多的顯卡廠商的廣泛支持。換句話說,用DirectX編程就完全可以不用去管顯卡的品牌和型號,專心和DirectX打好交道,剩下的由DirectX和Windows再交流解決了。

DirectX的DirectDraw用於2D繪圖,與Windows的API相比,DirectDraw更為安全,而且更增加了一些實用的方法用於圖形的轉換和修改。DirectInput則提供了用於管理輸入設備的方法,在這裡所有的Joystick都可以一律看待,極大的簡化了Joystick的使用。DirectMusic和DirectSound不用說大家也能想到是音樂和聲效的控制手段,盡管現在很多的游戲都采用MP3播放背景音樂,但是DirectMusic的方便和功能強大還是值得一看的。至於Direct3D和DirectPlay是用於3D繪制和聯網游戲,盡管都是正紅火的游戲形式,但因為D3D比較復雜,就只有留下D3D和DPlay以後再專門介紹了。由於DirectX本身是一套底層(low-level)的程序接口,也就是說它就是一套API,所以DirectX編程需要用到大量的指針用於對系統顯存和系統內存進行直接操作以換取更快的執行效率,所以起初DirectX使僅用於C++的。從DirectX7開始,DirectX都有VB的運行庫,那些復雜的指針操作統統被轉換成了普通的變量操作,這也就是為什麼能用C#開發DirectX程序的原因。

由於我今天才拿到DirectX8.1的SDK,所以這裡的程序都使用DirctX7vb運行庫開發。DirectX結構復雜,功能煩多,掌握起來並不像數據庫開發那麼明了,所以在此我僅僅是對其簡單的介紹其基本功能的介紹。但是也不用還怕DirectX下面的眾多功能接口的使用的基本方法是一樣的,歸結下來實現基本功能一般的必要步驟如下:

1.創建接口DirectX7.DirectXXXCreate();(XXX代表Input&Music&Draw….)

如:ddraw=dx.DirectDrawCreate("");

2.環境設置

如:

ddraw.SetCooperativeLevel(frm.Handle.ToInt32(),
             DxVBLib.CONST_DDSCLFLAGS.DDSCL_FULLSCREEN|
             DxVBLib.CONST_DDSCLFLAGS.DDSCL_ALLOWMODEX|
             DxVBLib.CONST_DDSCLFLAGS.DDSCL_EXCLUSIVE);

環境設置有時需要枚舉(enumerate)來獲得正確的可用設置.

3.創建操作實體

如:DDsurface=ddraw.CreateSurface(ref dDDesc);

4.對實體進行操作

如:DDsurfaceSpt.SetColorKey(DxVBLib.CONST_DDCKEYFLAGS.DDCKEY_SRCBLT,ref DDColorKey);

有了這4個步驟,也就基本上了解了DirectX編程的思路了,下面需要的就是尋找實現步驟的具體解決方法。我們先從DDraw開始,先做一個可以在背景上移動的(spriter)角色。然後再讓他走動時發出聲音(DSound),最後配上背景音樂(DMusic),這樣一個游戲的基本要素也就差不多齊全了,剩下該讓他干點什麼,就要看你的相像力了,在發揮想象力之前,還是先寫代碼吧!

建立一個project需要一個窗體(Form),引用Direct7 ,不要想引用DirectX8代替DirectX7,DirectX8沒有DirectDraw我也不知道為什麼沒有了,可能是在D3D表面也可以繪制2D的原因吧!接著我們可以去掉多余的引用留下System.,System.Windows.Forms和DxVBLib(它可是主角哦)就可以了。DirectX就是繪圖用的所以…System.Drawing就沒用了,不過還是把System.Drawing留下來,後面訪問Form位置的時候還是要用它。

接著定義DirectX7接口

private DxVBLib.DirectX7 dx=new DxVBLib.DirectX7();

好了准備工作已經做完了,下面就正式開始DirectDraw部分;

DirectDraw篇

DxVBLib.DirectDraw7 dDraw

按照剛才所說的步驟,先由dx-------DirectX7結構實體來創建一個DDraw接口實體用來完成後面的步驟;

DxVBLib.DirectDraw7 dDraw=dx. DirectDrawCreate(guid);

GUID是一個長達128位的結構(Structrue),是接口的代號對每一個借口都是不同的,可以用dx.CreateNewGuid()或者System.Guid.NewGuid().ToString()獲得。其實我們在這裡並不需要通過這個GUID接口來訪問DDraw接口的實體,所以讓GUID=""就可以了.

設置DDraw的顯示方式;

dDraw. SetCooperativeLevel(this.Handle.ToInt32(),
DxVBLib.CONST_DDSCLFLAGS.DDSCL_NORMAL);

frm就是當前窗體。這裡我們先建立一個非獨占的DDraw用來在我們的窗體上顯示圖像。

DxVBLib.CONST_DDSCLFLAGS.下面的對象可以用於DDraw模式的設置。
file://DxVBLib.CONST_DDSCLFLAGS.DDSCL_FULLSCREEN(全屏模式)
file://DxVBLib.CONST_DDSCLFLAGS.DDSCL_ALLOWMODEX(允許使用ModeX)
file://DxVBLib.CONST_DDSCLFLAGS.DDSCL_EXCLUSIVE(獨占模式)

上面幾種是常用的模式。其中後面兩種必須與DDSCL_FULLSCREEN一起使用。使用多個參數用以下格式

參數1|參數2|參數3

其它的DirectX的參數用法也是相同的,這些參數也就是一些功能的開關,直接會影響到顯示的效果。要了解其他參數最好還是看看在線幫助。

設置DirectDrawSurface7,Surface是DirectDraw用來存放圖像信息和顯示圖像的內存/顯存區域,也就是DDraw控制顯示圖像的實體。它是通過一個DDSURFACEDESC與之對應來設置,該存儲區的解釋方式,和信息格式等信息。並不是所有的Surface都是可見,有的Surface僅僅是用於存儲將要處理的圖像信息。因此,顯示的內存區域PRIMARYSURFACE和OVERLAY一般都在顯存。(OverLay需要硬件支持,一般用作桌面懸浮層,它的顯示區域是專門劃分的有別於普通的顯存)而其它的surface一般都是放在系統內存中,當然你也可以使用DSCAPS_VIDEOMEMORY/ DDSCAPS_SYSTEMMEMORY來指定surface存放的位置。我現在就需要兩個surface,一個作為Primary,另一個則是用作存放從硬盤讀取來的圖片數據。最後,再把數據轉換到Primary。

PrimarySurface如此之重要,是不能直接操作的。

DxVBLib.RECT rect,rectSec;
DxVBLib.DDSURFACEDESC2 dDDesc=new DxVBLib.DDSURFACEDESC2();
DxVBLib.DirectDrawSurface7 dDsurface;
DxVBLib.DDSURFACEDESC2 dDDesc1=new DxVBLib.DDSURFACEDESC2();
DxVBLib.DirectDrawSurface7 dDsurfaceSec;
dDDesc.lFlags=DxVBLib.CONST_DDSURFACEDESCFLAGS.DDSD_CAPS; dDDesc.ddsCaps.lCaps=DxVBLib.CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE;
dDsurface=dDraw.CreateSurface(ref dDDesc);
dDsurfaceSec=dDraw.CreateSurfaceFromFile("c:\\3.bmp",ref dDDesc1);
rect.Top=0;
rect.Left=0;
rect.Right=dDDesc1.lWidth; / /按圖片本身大小顯示
rect.Bottom= dDDesc1.lHeight;
dDsurface.BltFast(0,0,dDsurfaceSec,ref rect,DxVBLib.CONST_DDBLTFASTFLAGS.DDBLTFAST_WAIT);//將圖象在屏幕上顯示

由於我們使用的是BMP位圖文件也就是一個DIB文件,它的頭文件包含了調色板以及其他的一系列屬性,dDDesc1已經被設置過了,所以就不用再來設置了。RECT是用於控制顯示區域的結構體。Blt就是我們用來在surface之間轉換數據的方法,也就是畫圖的方法,其實與之類似的還有Flip,Flip方法使用一個緩沖層來避免過多在Primary上的切換以換取效率,具體方法還是看一下在線幫助,這裡就不作介紹了。BltFast的第一個參數和第二個參數用於控制IMAGE出現的頂點坐標(屏幕坐標系,單位長度為1個像素),RECT控制的是IMAGE是圖片的哪一部分圖片,所以這裡IMAGE所指定的是整幅圖片,也就是說我們可以局部的顯示圖片。運行的結果如下圖;

可以看到我們所繪制的圖片並不再frm的區域裡面。這是由於PrimarySurface代表的是整個可見區域,所以我們以0,0為起始繪圖自然不能保證在frm內,這個時候我們需要用另一個blt方法blt;代碼如下:

dx.GetWindowRect(this.Handle.ToInt32(),ref rectSec);
dDsurface.Blt(ref rectSec,dDsurfaceSec,ref rect,DxVBLib.CONST_DDBLTFLAGS.DDBLT_WAIT);

rectSec就將圖片限制在form所在的區域。效果如下:

這一次圖片的顯示區域已經被限制到窗體上了,可是還有一點問題,窗體上方的控制條被覆蓋掉了。這一次我們加入Clipper來限制圖片繪制的邊界。代碼如下:

dDclipper=dDraw.CreateClipper(0);
dDclipper.SetHWnd(this.Handle.ToInt32());
dDsurface.SetClipper(dDclipper);

Clipper取得的邊界是form的句柄傳遞的,所以Clipper所覆蓋的區域就是form的區域,這回我們可以看到正確的顯示了;

將代碼整理如下

private void draw()
{
dDraw=dx.DirectDrawCreate("");
DxVBLib.DirectDrawClipper dDclipper;
dDraw. SetCooperativeLevel(this.Handle.ToInt32(),DxVBLib.CONST_DDSCLFLAGS.DDSCL_NORMAL);
DxVBLib.RECT rect,rectSec=new DxVBLib.RECT();
DxVBLib.DirectDrawSurface7 dDsurface;
DxVBLib.DirectDrawSurface7 dDsurfaceSec;
dDDesc.lFlags=DxVBLib.CONST_DDSURFACEDESCFLAGS.DDSD_CAPS;
dDDesc.ddsCaps.lCaps=DxVBLib.CONST_DDSURFACECAPSFLAGS.DDSCAPS_PRIMARYSURFACE;
dDsurface=dDraw.CreateSurface(ref dDDesc);
dDclipper=dDraw.CreateClipper(0);
dDclipper.SetHWnd(this.Handle.ToInt32());
dDsurface.SetClipper(dDclipper);
dDsurfaceSec=dDraw.CreateSurfaceFromFile("c:\\3.bmp",ref dDDesc1);
dx.GetWindowRect(this.Handle.ToInt32(),ref rectSec);
rect.Top=0;
rect.Left=0;
rect.Right=dDDesc1.lWidth;
rect.Bottom= dDDesc1.lHeight;
dDsurface.Blt(ref rectSec,dDsurfaceSec,ref rect,DxVBLib.CONST_DDBLTFLAGS.DDBLT_WAIT);
}

現在只要在Form_Paint()和Form_Resize()中加入this.draw()任意改變窗體大小也可以正確顯示圖片了。接下來我們要在我們的Frm上來顯示我們的角色了;這樣我們還需要一個Surface,用來存放我們將要顯示的角色。角色運動是由很多的圖片連續播放的道德,一般我們都習慣於將這些圖片全部都做到一個文件裡面(如下圖),需要哪個角色就顯示那個區域就可以了。

代碼實現如下:

dDsurfaceActor=dDraw.CreateSurfaceFromFile("c:\\actorMove.bmp",ref dDDesc2);
rect.Top=0;
rect.Left=0;
rect.Bottom=dDDesc2.lHeight;
rect.Right=140;//Actormove.bmp每個動作之間的距離是140;顯示的是第一個動作;
rectSec.Top+=60;
rectSec.Left+=30;
rectSec.Bottom-=(rect.Bottom-rect.Top)/2;
rectSec.Right-=(rect.Right-rect.Left)/2;
dDsurface.Blt(ref rectSec,dDsurfaceActor,ref rect,DxVBLib.CONST_DDBLTFLAGS.DDBLT_WAIT);

我們看到的角色只是實際圖片的一部分

由於原圖本身背景是黑色的,blt的時候就連角色一起畫進去了。這個時候我們需要用到colorKey來屏蔽我們不需要的背景色。代碼段如下:

DxVBLib.DDCOLORKEY dDcolorKey=new DxVBLib.DDCOLORKEY();
dDcolorKey.high=20; file://被屏蔽
dDcolorKey.low=0; file://的顏色介於這兩者之間
dDsurfaceActor.SetColorKey(DxVBLib.CONST_DDCKEYFLAGS.DDCKEY_SRCBLT,ref dDcolorKey);
dDsurface.Blt(ref rectSec,dDsurfaceActor,ref rect, DxVBLib.CONST_DDBLTFLAGS.DDBLT_WAIT |DxVBLib.CONST_DDBLTFLAGS.DDBLT_KEYSRC);

這會就可以看到正確的人物了。

到這裡DirectDraw的工作就只是剩下鍵盤的響應函數就已經基本實現了一個簡單的游戲地圖引擎了,是不是也並不是很難?至於鍵盤相應函數原理很簡單,只要在鍵盤按下的時候刷新form然後按順序顯示人物圖標同時rect的值隨之改變就可以了。要是有興趣的話可以自己試試看。DirectDraw繪圖的速度很快,除了做游戲外還可以用來播放AVI甚至是MEPG文件或者是屏保,只要搭配相應的文件轉換和解碼模塊使用就可以。好了,關於DirectDraw的介紹就道這裡了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved