VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > temp > C#教程 >
  • DirectDraw之C#入门攻略

制作者:剑锋冷月 单位:无忧统计网,www.51stat.net
 

  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.创建接口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位置的时候还是要用它。



相关教程