首先在上面的程序中加入一个函数SetNewDisplayMode,函数代码如下:
Private Function SetNewDisplayMode() On Error GoTo ErrHandler Dim ddsd As DDSURFACEDESC2 Dim i As Long i = List1.ListIndex If i = -1 Then MsgBox "请在列表中选择一种显示模式",vbOKOnly,"错误" Exit Function End If objEnumModes.GetItem (i + 1),ddsd ''设置协作模式 objDraw.SetCooperativeLevel Me.hWnd,DDSCL_FULLSCREEN Or _ DDSCL_ALLOWMODEX Or DDSCL_EXCLUSIVE ''设置显示模式 objDraw.SetDisplayMode ddsd.lWidth,ddsd.lHeight,_ ddsd.ddpfPixelFormat.lRGBBitCount,_ 0,DDSDM_DEFAULT Me.Refresh ErrHandler: Select Case Err.Number Case 0 ''No Errors Case Else Err.Raise Err.Number,Err.Source,Err.Description,Err.HelpContext,_ Err.HelpContext Call Cleanup End Select End Function 在Command2的Click事件中加入以下代码: Dim i For i = 0 To Form1.Controls.Count - 1 Form1.Controls(i).Visible = False Next i SetNewDisplayMode |
再次运行程序,点击列表中的任意一个显示模式,然后点击"设置显示模式"按钮,可以看到屏幕的显示模式被设置成了你在列表中选择的模式。
上面介绍的是如何设置显示模式,下面介绍如何利用DirectSurface对象来进行图形绘制以及如何利用前台绘图平面同后台绘图平面相配合工作。这个程序要实现的目的是:在屏幕上显示一幅背景位图,然后有一个角色在屏幕上移动。为了实现上面的目的,我们需要建立四个绘图平面,一个主平面,就是程序运行时可以看到的平面;一个后台缓冲平面,用于进行图像操作;一个位图平面,用于显示背景位图;一个角色位图平面,用于显示角色位图。在程序运行时首先将背景位图贴到后台缓冲平面,然后将角色位图平面贴到后台缓冲平面,在后台缓冲平面输出一些提示文字,最后将后台缓冲平面的内容贴到主平面上。
为完成下面的 程序,首先要在你的工程文件的目录下建立一个名字为Demo.bmp的位图文件最为背景和一个名字为 Sprite.bmp 的位图作为角色位图。在Form1中加入一个ListBox控件和两个CommandButton控件。加入Directx7说明库,然后在Form1的代码窗口中添加以下的代码:
Option Explicit Dim objDx As New DirectX7 Dim objDraw As DirectDraw7 Dim objEnumModes As DirectDrawEnumModes Dim MainSurf As DirectDrawSurface7 Dim BackSurf As DirectDrawSurface7 Dim BmpSurf As DirectDrawSurface7 Dim SpriteSurf As DirectDrawSurface7 Dim ddsd As DDSURFACEDESC2 Dim ddsd1 As DDSURFACEDESC2 Dim ddsd2 As DDSURFACEDESC2 Dim ddsd3 As DDSURFACEDESC2 Dim ddsd4 As DDSURFACEDESC2 Dim ddsd5 As DDSURFACEDESC2 Dim bRun As Boolean Dim lastTime As Long Dim fps As Long Dim lfps As Long Dim FrameCount As Long Dim Clipper As DirectDrawClipper Dim x As DDPIXELFORMAT Dim sx,sy As Integer Dim Pict() As Byte Sub InitSurf() On Error GoTo ErrHandler '设置主绘图平面的属性 ddsd1.lFlags = DDSD_CAPS Or DDSD_BACKBUFFERCOUNT ddsd1.lBackBufferCount = 1 ddsd1.ddsCaps.lCaps = DDSCAPS_COMPLEX Or DDSCAPS_FLIP Or DDSCAPS_PRIMARYSURFACE '设置缓冲绘图平面的属性 ddsd2.ddsCaps.lCaps = DDSCAPS_BACKBUFFER '根据ddsd1建立主绘图平面 Set MainSurf = objDraw.CreateSurface(ddsd1) '将BackSurf设置为MainSurf的附加平面 Set BackSurf = MainSurf.GetAttachedSurface(ddsd2.ddsCaps) '设置背景绘图平面的字体和颜色 BackSurf.SetForeColor RGB(255,255,255) Form1.Font.Name = "宋体" BackSurf.SetFont Form1.Font '获得缓冲绘图平面的属性并设置到ddsd4中 BackSurf.GetSurfaceDesc ddsd4 '设置图形绘图平面的属性 ddsd3.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH ddsd3.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN ddsd3.lWidth = ddsd4.lWidth ddsd3.lHeight = ddsd4.lHeight '建立图形绘图平面 Set BmpSurf = objDraw.CreateSurfaceFromFile(App.Path + "/demo.bmp",ddsd3) '设定角色位图平面的属性 ddsd5.lFlags = DDSD_CAPS ddsd5.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN '建立角色位图平面 Set SpriteSurf = objDraw.CreateSurfaceFromFile(App.Path + "/sprite.bmp",ddsd5) Dim key As DDCOLORKEY '设定透明色(在这里设定为0,黑色) key.low = 0 key.high = 0 SpriteSurf.SetColorKey DDCKEY_SRCBLT,key sx = 20: sy = 20 lastTime = objDx.TickCount While True DoEvents Blt Wend ErrHandler: Select Case Err.Number Case 0 ''No Errors Case Else '错误退出 Call Cleanup End Select End Sub Sub Blt() Dim mrectScreen As RECT Dim sTimePass As Single Dim sFramePerS As Single '以黑色清除并填充后台绘图平面 BackSurf.BltColorFill mrectScreen,0 '获得背景位图平面的矩形区域的尺寸 mrectScreen.Right = ddsd2.lWidth mrectScreen.Bottom = ddsd2.lHeight '将图形绘图平面中的内容复制到后台绘图平面上 Call BackSurf.BltFast(0,BmpSurf,mrectScreen,DDBLTFAST_WAIT) '获得前景角色位图平面的矩形区域 mrectScreen.Right = ddsd5.lWidth mrectScreen.Bottom = ddsd5.lHeight '将前景角色位图复制到后台绘图平面上。 Call BackSurf.BltFast(sx,sy,SpriteSurf,DDBLTFAST_SRCCOLORKEY) sx = sx + 2: sy = sy + 2 If sx > 400 Then sx = 20 If sy > 400 Then sy = 20 '在后台绘图平面上输出文本 BackSurf.DrawText 30,30,"This is my first DirectX program",False BackSurf.DrawText 30,60,"点击屏幕退出程序",False '获得每秒的播放帧数。 FrameCount = FrameCount + 1 sTimePass = (objDx.TickCount - lastTime) / 1000 If sTimePass > 0.5 Then sFramePerS = FrameCount / sTimePass End If BackSurf.DrawText 30,90,"每秒帧数:" + Format$(sFramePerS,"##00.0"),False '将后台绘图平面上的内容翻转到前台来 MainSurf.Flip Nothing,DDFLIP_WAIT End Sub Private Function SetNewDisplayMode() On Error GoTo ErrHandler Dim i As Long i = List1.ListIndex If i = -1 Then MsgBox "请在列表中选择一种显示模式","错误" Exit Function End If '获得用户选择的显示模式 objEnumModes.GetItem (i + 1),DDSCL_FULLSCREEN Or DDSCL_ALLOWMODEX _ Or DDSCL_EXCLUSIVE ''设置显示模式 objDraw.SetDisplayMode ddsd.lWidth,ddsd.ddpfPixelFormat.lRGBBitCount,DDSDM_DEFAULT Me.Refresh ErrHandler: Select Case Err.Number Case 0 ''No Errors Case Else Err.Raise Err.Number,_ Err.HelpContext Call Cleanup End Select End Function Sub Cleanup() 'Cleanup函数回复屏幕并且清除DirectX对象 Call objDraw.RestoreDisplayMode Call objDraw.SetCooperativeLevel(Me.hWnd,DDSCL_NORMAL) Set objDraw = Nothing Set objDx = Nothing End End Sub Private Sub Command1_Click() End End Sub Private Sub Command2_Click() Dim i For i = 0 To Form1.Controls.Count - 1 Form1.Controls(i).Visible = False Next i SetNewDisplayMode InitSurf End Sub Private Sub Form_Click() Cleanup End Sub Private Sub Form_Load() Command1.Caption = "结束" Command2.Caption = "设置显示模式" On Error GoTo ErrHandler: Dim ddsd As DDSURFACEDESC2 Dim i As Long,lgCount As Long Set objDx = New DirectX7 '建立 DirectDraw 对象 Set objDraw = objDx.DirectDrawCreate("") '将DirectDraw对象支持的显示模式设置到DirectDrawEnumModes对象中 Set objEnumModes = objDraw.GetDisplayModesEnum(DDEDM_DEFAULT,ddsd) '将数据设置到ListBox中 lgCount = objEnumModes.GetCount() For i = 1 To lgCount objEnumModes.GetItem i,ddsd List1.AddItem CStr(ddsd.lWidth) & "x" & CStr(ddsd.lHeight) & "x" _ & CStr(ddsd.ddpfPixelFormat.lRGBBitCount) Next i ErrHandler: Select Case Err.Number Case 0 ''没有错误 Case Else Err.Raise Err.Number,_ Err.HelpContext Call Cleanup End Select End Sub |
现在程序全部完成了,运行程序,点击列表中的任意显示模式,然后点击"设置显示模式"按钮,可以看到位图被显示在屏幕上并且在屏幕上显示出程序中的文本。
上面的程序比较简单,但是包含了基本的DirectDraw的应用,下面来分析一下:
首先通过DirectX7的DirectDrawCreate方法建立一个DirectDraw对象,然后通过GetDisplayModesEnum方法获得DirectDraw对象支持的显示模式,当选择某一种显示模式之后,调用DirectDraw对象的SetDisplayMode方法设置所选择的显示模式。
接下来是设置绘图平面,如果对于 游戏编程有一些了解的朋友都会知道,为了不使在游戏的图像切换时发生闪烁,我们一般需要设置一个后台绘图平面,对所有的画面首先在后台缓冲平面上做所需要的处理,然后再将它翻转到前台来。从上面的程序可以看到,在程序中一共设置了三个不同的绘图平面:MainSurf、BackSurf、BmpSurf、SpriteSurf。MainSurf是主绘图平面,是程序运行时可以看到的部分;而BackSurf是后台绘图平面;BmpSurf是背景位图平面;SpriteSurf是角色位图平面。我们使用MainSurf的GetAttachedSurface方法将BackSurf设置为MainSurf的附加平面,所有的图形操作首先在在BackSurf上进行,然后在翻转到主平面上来。BmpSurf在程序中利用DirectDraw的CreateSurfaceFromFile函数被设置为一个包含位图的绘图平面。SpriteSurf也做同样的设定,但是为了使只有角色显示出来而无关的部分不显示,我们需要设置SpriteSurf的ColorKey,在上面设置为0黑色,即在粘贴图像时Sprite.bmp 中的黑色部分不会显示出来。然后建立一个无限循环,在每个循环内首先将BmpSurf上的位图转贴到BackSurf上,然后在BackSurf上输出文字,等在BackSurf上的操作全部完成之后,再利用MainSurf的Flip方法将后台绘图平面的内容翻转到前台平面上来。读者需要注意的是这四个绘图平面的不同属性(从ddsd1到ddsd5)。