关于使用C#和directX进行游戏编程,自从DirectX9问世以来,变得很容易,网上这方面的资源也很多。我这里记录的是一个比较特殊的case。这是一个2D的游戏编程。我放弃了direct9,因为如果只是2D,主要使用的是directdraw, 自从directx 8以上的版本,direct draw 都被合并到direct3D里面去了,所以使用directdraw需要3D的知识。而且它需要 directx 3D card,所以即便有时候它可能更方便,但是会提到对客户机的hardware的要求。我在这个游戏里使用的是directx vb type library。因为这样的话,运行游戏就不需要同时安装directX run time,而且对客户机的hardware的要求也大大降低了。我发现这方面的资源还是相对很少的,或者很零散,我希望自己可以有毅力把自己的心得以及搜集到的资料整理起来,欢迎有兴趣的朋友补充。下面的这篇日志是我在一篇文章的基础上加上我自己的心得改写的,因为我觉得它有的地方解释的不够仔细或者不是完全精确:)
另外想说的是游戏编程,C#绝对不是一种好的语言:)既然它要求安装额外的run time。
最初的DirectX多媒体开发仅仅适用于C/C++的编译环境,但是微软自从DirectX7.0版本(目前DirectX的最高版本9.0测试版已经公布)推出以后,就开始提供VB开发库,支持在VB环境下开发基于DirectX的多媒体应用程序。如果要进行DirectX开发,系统必须安装DirectX SDK库并且要在VB项目中引入它。
我的体会是如果不使用directX 9.0以上的版本,要想在C#中使用directx,就必须使用directX vb type library。而且使用这个library,不需要安装directx sdk,只需要引用必须的dll就可以了。
为了进行DirectDraw的编程,需要读者特别注意的一点是,在点击VB菜单中的 Project | References 项引入DirectX 为VB提供的SDK库时,在Object Library 列表中要选择DirectX7.0 For Visual Basic Type Library 这个列表项。为什么不选择DirectX8.0或更高版本提供的类库呢?因为只有DirectX7.0提供了DirectDraw对象,在后续的DirectX版本中,DirectDraw 已被融入Direct3D对象中了,而Direct3D对象主要用于三维立体图像的处理,它的使用比较复杂,而且要求安装directX 3D卡。
DirectX7.0技术简介
为了更好的介绍DirectDraw编程,我们首先简单介绍一下DirectX7.0技术,使读者对它有一个初步的印象,至于DirectX的后续版本,只是在7.0版本的基础上添加了一些新的功能和作了一些结构调整罢了,相关内容读者可以自己参阅MSDN。DirectX7.0提供的开发库是基于对象的,其中最基本的对象是DirectX7对象,只有在程序中首先建立了DirectX7对象之后才可以在该对象的基础上建立其它对象。DirectX基本对象包含以下几个常用的类:
1)DirectDraw类,独立于设备的表面绘图对象,支持以全屏方式或者窗口方式绘图,同时DirectDraw实现了对显卡内存的直接操作(也可以实现对系统的内存的操作,如果在显卡内存不够或者开发人员指定使用系统内存的情况下,DirectDraw将操作系统内存),一旦定义DirectDraw对象并锁定,就可以象操作一个数组一样操作内存中的图像数据了。
2)独立于设备的Direct3D类,包括立即模式和保留模式,它是DirectX的三维绘图接口、开发三维DirectX游戏的基础。
3)DirectSound类, DirectX中独立于设备的Wave音频对象,支持混音、硬件加速、直接设备访问、声音捕捉和回放。
4)DirectMusic类,音乐数据文件操作对象,支持DLS(downloadable sounds)标准和运行时编辑。
5)DirectInput类,独立于设备的游戏控制器对象,支持操作映射,过操作映射能够在输入操作和输入设备之间建立连接。您只需输入设备处理,而不必再依赖特定的设备对象。用于支持鼠标、键盘、游戏杆。
6)DirectPlay类,为支持多任务的网络游戏而设计的对象,可以协调速度不同的计算机之间的信息传递以支持不同的计算机用户通过网络进行互连。
DirectX7对象包含了诸如建立DirectDraw、 Direct3D、 DirectSound、 DirectInput等对象的方法,例如,当建立成功一个DirectX7对象之后,就可以使用该对象的DirectDrawCreate、Direct3DRMCreate等方法建立DirectDraw、Direct3D对象了。
DirectDraw编程
正如上节介绍的那样,DirectDraw提供了与硬件无关性的同时允许直接操作显存,它是一个与Windows 图形系统接口(GDI)相兼容的直接操作显示设备的软件接口,是DirectX技术中进行图像处理的基础,是DirectX中的关于视频输入输出的基本部分,只要使用的硬件支持DirectDraw,开发人员就可以使用DirectDraw可以方便地编制出高效的视频处理、图像处理的程序来。
DirectDraw类包含DirectDraw7、DirectDrawClipper 、DirectDrawEnumModes、 DirectDrawPalette、DirectDrawSurface7等对象。其中,DirectDraw7对象是DirectX7中的DirectDraw对象,你需要首先建立一个DirectX7对象,然后使用该对象的DirectDrawCreate方法来建立DirectDraw7对象。
DirectDraw7的GetDisplayModesEnum方法可以建立一个DirectDrawEnumModes对象,通过它可以获得当前系统支持的显示模式;DirectDraw7的CreatePalette方法可以建立一个DirectDrawPalette对象,DirectDrawPalette对象是DirectDraw下的绘图调色板对象,它很类似于Windows下的调色板。
利用DirectDraw7的CreateClipper方法可以建立一个DirectDraw7下的DirectDrawClipper对象,DirectDrawClipper对象的作用是建立一个屏幕的剪裁区域,这样DirectDraw就知道绘图时那些部分是可见的而那些部分应该被剪裁掉。
DirectDrawSurface7是DirectDraw下的最重要的对象,这个对象描述了一块线型的显存区域,我们所进行的所有图形、文本操作都是在这个对象上进行的,你可以通过DirectDrawSurface7对象直接操作这片区域。
通过DirectDraw7的CreateSurface方法,可以建立一个单一绘图表面、复合绘图表面或者三维绘图表面对象。而利用DirectDraw7的CreateSurfaceFromFile方法、CreateSurfaceFromResource方法可以分别根据位图文件和位图资源建立一个包含图像数据的 DirectDrawSurface7对象。
仅仅知道如何创建DirectDraw编程需要使用到的一些对象是远远不够的,还需要使用灵活的使用这些对象提供的方法,下面按照DirectDraw处理图像的步骤来说明这些方法的使用。
1、建立协作层
当建立了一个DirectDraw对象之后,首先要设定DirectDraw的协作层。实现的方法是调用DirectDraw对象的SetCooperativeLevel函数。该函数的定义是:
SetCooperativeLevel( hdl As Long, flags As CONST_DDSCLFLAGS)
其中参数hdl指定程序的窗口句柄,参数flag决定程序运行的方式,它的值可以使用Or组合起来。具体值的含义如下:DDSCL_FULLSCREEN表示使用全屏幕(必须和DDSCL_EXCLUSIVE一起用)、DDSCL_ALLOWMODEX使用Modex模式、DDSCL_EXCLUSIVE 使用独占模式、DSCL_NORMAL 使用Windows的窗口、DDSCL_NOWINDOWCHANGES 禁止改变窗体大小。例如函数调用SetCooperativeLevel Me.hWnd, DDSCL_NORMAL将使程序运行于普通的协作层既窗口模式之下,在这种协作层你无法改变主表面调色板或进行页交换。而函数调用SetCooperativeLevel MainForm.hWnd, DDSCL_EXCLUSIVE Or _DDSCL_FULLSCREEN将使程序运行于全屏幕模式之下。在全屏幕协作模式之下你可以完全使用硬件的一切,你可以设置自己的调色板,改变显示分辨率及进行页交换。
2、设置显示模式
设置系统的显示模式是使用DirectDraw的SetDispalyMode函数实现的,函数的定义如下:
SetDisplayMode( w As Long, h As Long, bpp As Long, ref As Long, mode As CONST_DDSDMFLAGS)
其中参数w、h分别指定屏幕的宽度和高度,bpp指定屏幕显示的颜色位数,参数ref指定屏幕的刷新频率,设置为0使用显示驱动的缺省刷新频率,mode指定附加的参数。为了保证程序的健壮性,需要获得系统支持的显示模式,此时可以使用DirectDraw对象的GetDisplayModesEnum函数来遍历所有支持的显示模式,然后根据返回的结果进行设置。
3、建立DirectDrawSurface表面对象显示图像
DirectDrawSurface对象是DirectDraw用来进行图像显示和绘制的对象,开发人员不仅可以在DirectDrawSurface上贴位图、绘制图形,还可以直接操作DirectDrawSurface对象来处理显存或内存里的图像数据。一般来说它分成以下几种类型:primarysruf surface(主表面), 屏幕上可以看到的显示记忆体,图像画在上面就能显示在屏幕上;backsurf surface (后备表面),这是一个能跟primarysruf surface作快速切换的表面;offscreen surface (离屏表面),这是一个屏幕上看不见的Surface,主要用来存放图像数据。
利用DirectDraw对象的CreateSurface方法可以建立一个DirectDrawSurface7对象,设置DDSURFACEDESC2结构对象的不同标志可以实现不同的表面对象。为了改善图像显示效果,在DirectDraw编程时,一般设立一个主表面、后备表面和若干个离屏表面,主表面就是用户看到的显示图像的表面,也就是当前显示的表面,后备表面是主表面的附带缓冲表面,用来存储、处理即将显示的图像,离屏表面用来装载最初的图像数据,可以利用DirectDraw对象的CreateSurfaceFromFile函数或者CreateSurfaceFromResource函数建立一个DirectDrawSurface7对象,同时将图象文件或者资源文件中的图像装入建立的 DirectDrawSurface中,该函数调用成功后返回一个DirectDrawSurface对象。
处理后使用Blt函数将数据拷贝到后备表面,此时DirectDraw使用filp方法交换主表面和后备表面,其实就是交换指针,后备表面变为主表面显示图像,先前的主表面变为后备表面,这样作既提高的图像数据的处理速度,又有效的避免图像闪烁,这叫做page flipping(翻页)。