DirectDraw之C#入门攻略
DirectX的DirectDraw用于2D绘图,与Windows的API相比,DirectDraw更为安全,而且更增加了一些实用的方法用于图形的转换和修改。DirectInput则提供了用于
由于我今天才拿到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部分;

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一般都是放在
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);//将图象在 |
![]() |
可以看到我们所绘制的图片并不再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所在的区域。
![]() |
这一次图片的显示区域已经被限制到窗体上了,可是还有一点
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的工作就只是剩下键盘的响应函数就已经基本实现了一个简单的