程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> Visual Basic語言 >> VB6 >> GIFs、JPGs和DirectInputMouse在VB游戲編程中的運用

GIFs、JPGs和DirectInputMouse在VB游戲編程中的運用

編輯:VB6

相對而言,不是很難,我們並不需要解碼器來得到JPG的每一個字節,或任何類似於次的,相反,我們將用一個圖片框來打開一個圖片,然後再將其傳到表面,但首先我門需要聲明API函數:

Public Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long

Public Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long

Public Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long

Public Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long

Public Declare Function StretchBlt Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal dwRop As Long) As Long

現在我們要為加載圖片作好准備

Dim Pict1 As StdPicture

Set Pict1 = LoadPicture("MyPict.jpg")

創造表面:

Dim TDesc As DDSurfaceDesc2

TDesc.lFlags = DDSD_CAPS Or DDSD_HEIGHT Or DDSD_WIDTH

TDesc.ddsCaps.lCaps = DDSCAPS_OFFSCREENPLAIN

TDesc.lHeight = CLng((Pict1.Height * 0.001) * 567 / Screen.TwipsPerPixelY)

TDesc.lWidth = CLng((TPict.Width * 0.001) * 567 / Screen.TwipsPerPixelX)

Set Surf = DDraw.CreateSurface(TDesc)

Dim SurfDC As Long, PictDC As Long

SurfDC = Surf.GetDC

PictDC = CreateCompatibleDC(0)

SelectObject Pict1.Handle, PictDC

我們將使用Dcs和Bitblt或StretchBlt來把Pic1復制到表面

只復制成一樣大小:

BitBlt SurfDC, 0, 0, TDesc.lWidth, TDesc.lHeight, PictDC, 0, 0, vbSrcCopy

現在復制並且改變圖片大小

StretchBlt SurfDC, 0, 0, StretchWidth, StretchHeight, PictDC, 0, 0, TDesc.lWidth, TDesc.lWidth, vbSrcCopy

釋放DC:

Surf.ReleaseDC SurfDC

DelecteDC PictDC

Set Pict1 = Nothing

下一步該怎麼作呢?下載SurfUtil。Bas,我將利用這一技巧來創造並加載圖片

注意:有時StretchBlt不能正常顯示GIF,那就是我添加了BitBlt這個函數的原因

.

特殊效果

你會懶的不想利用C/C++或匯編來創造一個動態連接庫,並用那個動態連接庫來完成特殊效果嗎?

就讓blitter(我不認識,也查不出來,可能是glitter,閃光)光柵操作(ROP)為你工作!

我的格言是讓最小的努力為你帶來最大的報酬!

在Vb中有不少可使用的ROP常數:

vbSrcPaint -邏輯或操作,源和目標圖片,做一個模擬的Alpha混合效果。

vbSrcAnd - 邏輯與操作,灰度效果。

vbSrcInvert - 邏輯異或操作。

vbSrcErase - 翻轉目標圖片,然後再和源圖片進行邏輯與操作

vbSrcCopy - 把原圖片直接復制到目標圖片上,在圓滿的替換掉?(replacing it completely)

vbDstInvert -翻轉目標圖片,全部忽略原圖片。

vbNotSrcCopy -翻轉源圖片,然後在直接復制到目標上,又是圓滿的替換掉?(replacing it completely)

vbNotSrcErase - 對源圖片和目標圖片進行邏輯或操作,在翻轉。

現在我們利用這些ROP有兩個執行銷毀的方法。我們能夠使用APIBitBlt這個函數,,也可以使用DirectX的BltFx函數,只有用戶的顯卡能夠使用硬件來支持ROP而不是軟件模擬ROP,BltFx才能夠工作,否則BltFx將會失敗!無論怎樣,BltFx失敗時,API的BitBlt還是能夠調用,在軟件中,一切就緒時,BitBlt就決不會失敗!

(深思熟慮:當使用BltFx時,它可以完美的將表面放到顯存以使其借助顯卡的Blitter(和上面的一樣,不認識也查不出來)來快速訪問,而當另外使用API函數BitBlt時,它卻完美的將其置放到系統內存,否則數據將會被從顯存中修改後帶來,然後它將回到顯存,沒有效率啊!)

容易的知道確認用戶的顯卡是否硬件支持特殊的ROP是件很好的事,我寫了一個簡單的函數來確認:

Private Function TestROP(ByRef surfBack As DirectDrawSurface7, lngROP As Long) As Boolean

Dim objBltFx As DDBLTFX

Dim rectTemp As RECT

Dim surfTemp As DirectDrawSurface7

Dim udtDDSD As DDSURFACEDESC2

'創造一個臨時的表面

udtDDSD.lFlags = DDSD_HEIGHT Or DDSD_WIDTH

udtDDSD.lHeight = 1

udtDDSD.lWidth = 1

Set surfTemp = mdd.CreateSurface(udtDDSD)

'設置BltFx的ROP操作代碼

objBltFx.lROP = lngROP

'源和目標矩形

rectTemp.Right = 1

rectTemp.Bottom = 1

'測試BltFx 的能力

If surfBack.BltFx(rectTemp, surfTemp, rectTemp, DDBLT_ROP Or DDBLT_WAIT, objBltFx) <> 0 Then

TestROP = False

Else

TestROP = True

End If

End Function

簡單的傳遞這個函數 一個參考到你的當前後備緩存和你感興趣的ROP常數,它將把用戶硬件是否支持特殊的ROP告訴你給你,它執行一個BltFx 的blit例子並且測試錯誤然後返回錯誤。

(注:這一段如果你懂就可不必看我寫的,有一些英文短語不容易翻譯成中文)

Simply pass this function a reference to your current backbuffer and the ROP constant you're interested in and it will inform you of the user's hardware capabilities. It does this by performing a sample BltFx blit and examining the error code returned.

現在我門知道如果我們希望的ROP已經被支持,我們就能往下繼續並且執行我們的blit,如果ROP以被支持,我們也能像這樣使用BltFx:

objBltFx.lROP = lngROP

msurfBack.BltFx rectDest, surfDisplay, rectSource, DDBLT_ROP Or DDBLT_WAIT, objBltFx

objBltFx的定義類型是DDBLTFX,必須和我們希望執行(被儲存在lngROP中)的ROP一起被加載。一次,我們有我們的DDBLTFX類型填充,我們就能使用後備緩存的BltFx方法,傳遞源和目標矩形、我們期望的表面、一點常數(DDBLT_ROP和DDBLT_WAIT)和objBltFx,常數DDBLT_ROP是必須的,它將通知BltFx我們想使用DDBLTFX結構的成員lROP。If we're forced to use the BitBlt API, it can be handled in this fashion:

'鎖主表面的DCs

lngDestDC = msurfBack.GetDC

lngSrcDC = surfDisplay.GetDC

'Do the fancy old-fashioned blit

BitBlt lngDestDC, intX, intY, intWidth, intHeight, lngSrcDC, 0, 0, lngROP

'釋放DCs

surfDisplay.ReleaseDC lngSrcDC

msurfBack.ReleaseDC lngDestDC

首先我們需要得到源(被blitte的表面,和上文的blitter有關,可能是DirectX的專有名詞)和目標(後備緩存)的DC,一旦我們全部擁有,我們把它們作為BitBlt的參數,再和妖怪定義(?sprite的確是妖怪)和我們期望的ROP(lngROP)向前,然後必須釋放DC,以免電腦當掉。

(First we need to acquire the source (surface to be blitted) and destination (backbuffer) DCs. Once we have them, we feed this data into the BitBlt call, along with our sprite dimensions and the ROP we desire (lngROP). Afterward we MUST release the DCs, lest we freeze the computer)

現在你得到了它!一點魔法般的函數,能讓你在你的程序或游戲中使用這些漂亮的光柵,把源代碼下載下來,來看看所有不同的ROP的效果吧!

So there you have it! A few magic little functions and you can employ nifty raster operations in your games and programs. Download the source to see all of the different ROPs in action.

推薦的DirectInput Mouse處理

這裡有很多你看起來比較熟悉的東東,那時因為我學到的大部分關於在DirectX7中使用鼠標是來自Lucky的DirectInput教程,我僅僅超過教程的一點點,在這個教程中你間看到如何“剪下”鼠標當它正從屏幕上離開的時候,怎樣將“Hot Spots”(關於Hot Spots請參考人民郵電出版社的《Visual Basic 6.0 和Windows API 講座第十五章597頁》)添加到鼠標的指針上,把鼠標指針放到DX的表面上的確很好,它首先能幫你閱讀Lucky的DirectInput教程,如果你還沒有,我不想解釋你在這裡能學到什麼。

你將注意到當你在Windows中移動鼠標時,你將會注意到你把它只能移到底部或右部,直到坐標只剩一個像素(鼠標的X,Y坐標只剩一個像素)。如果你試著去在DX中用鼠標指針的任何一部分來畫你的鼠標指針(甚至是不顯示的部分),當 離開屏幕/DX表面時,似乎要忽略那條線,那是因為你不能在表面外畫任何東東,不可能發生這種情況。所以我們需要把我們看不到,在屏幕外的部分剪下來。

事實上,在Windows中,你若真的做了以上多提到的,將會隱藏你鼠標的“Hot Spot”,你的鼠標指針同樣會停止上下左右的移動,其實,HotSpot就是你鼠標指針在Windows上的一個像素,你的鼠標指針對Windows而言,不是32×32像素,它只是一個單一的像素,Windows僅僅將其圍繞這那個像素來畫鼠標指針,以使你看起來像個鼠標指針,僅僅看起來像,如果你的鼠標的HotSpot大小是32×32像素,那麼你將會更有可能同時點擊不止一個的按鈕,如果按鈕都彼此很近,那麼換而言之,一個HotSpot就是鼠標指針中最重要的一個像素,其余的就當是陪襯,例如箭頭,鋼筆的頂端,或改變窗體大小的指針的中間就是它的HotSpot。

OK,讓我們試著從一個鼠標指針中得到HotSpot。

你將需要這些變量和聲明:

'檢測和剪切鼠標

Declare Function IntersectRect Lib "user32" (lpDestRect As RECT, lpSrc1Rect As RECT, lpSrc2Rect As RECT) As Long

'聲明為DirectX7的變量!

Global DXMouse As New DirectX7

'The DirectInput object! DOUBLE-DUH!

Global DXMouseInput As DirectInput

'Input Device object we'll use for the mouse

Global DXMouseInputDev As DirectInputDevice

'Mouse state type

Global DXMouseState As DIMOUSESTATE

'鼠標移動的速度

Global Const MOUSE_SPEED = 1

'鼠標能移動的矩形范圍

Global Mouse_Rect As RECT

'鼠標指針的X(橫)坐標

Global DXMouseX As Integer

'鼠標指針的Y(縱) 坐標

Global DXMouseY As Integer

'鼠標左鍵是否被按下?

Global DXLeftMouseButton As Boolean

'鼠標右鍵是否被按下?

Global DXRightMouseButton As Boolean

'鼠標HotSpot所在的矩形On Mouse Hot Spot Rectangle

Global HotSpot_Rect As RECT

'鼠標的HotSpot X坐標

Global DXMouseHotX As Integer

'鼠標的HotSpot Y 坐標

Global DXMouseHotY

'是否顯示鼠標

Global DXMouseVisible As Boolean

那些就是Lucky對源文件教程的評價,我可不想抄襲Lucky的,就像我前文所說的“我所學到的大部分是關於DirectX7鼠標是來自Lucky的DirectInput教程”,我做了少許關於變量名的改變是因為他的變量名並沒有是我感覺到什麼。

現在,4個新的東東分別是HotSpot_Rect,DXMouseHotX,DXMouseHotY,和DXMouseVisible。

HotSpot_Rect 就是讓我們每每改變RECT時讓我們直到的東東:當HotSpot在屏幕上時,他只會有一個像素那麼大。

DXMouseHotX和DXMouseHotY是鼠標指針上HotSpot的X 和Y坐標:最左邊的頂端被定義為(1,1)

DXMouseVisible僅僅是一個告訴我們如果我們准備將鼠標畫到屏幕上的布爾值,因為有時我們並不想這樣做

Now comes the Initialization Sub. Again this is the exact same thing in Lucky's Source, but I changed the variable names so we can all understand them.

現在有個初始化的過程,這和Lucky的源代碼一樣准確(其實就是一樣),但是我改變了變量名,所以我們能夠更容易的懂得。

Sub Initialize()

'如果我們不能正常的初始化,逮住錯誤

On Error Resume Next

'創造一個DirectInput部件

Set DXMouseInput = DXMouse.DirectInputCreate()

'將鼠標作為diMouse設備來跟蹤

Set DXMouseInputDev = DXMouseInput.CreateDevice("GUID_SysMouse")

'得到鼠標輸入設備的唯一性,但只有在前景模式時才有效

DXMouseInputDev.SetCommonDataFormat DIFORMAT_MOUSE

DXMouseInputDev.SetCooperativeLevel frmMain.hWnd, DISCL_FOREGROUND Or DISCL_EXCLUSIVE

DXMouseInputDev.Acquire

'初始化鼠標的變量

DXMouseX = 0

DXMouseY = 0

DXLeftMouseButton = False

DXRightMouseButton = False

End Sub

在此我不想解釋任何事,你將必須看看Lucky的教程和源代碼來為你自己解釋

現在,給新的材料加點舊的材料

Sub DXMouseRefresh()

'刷新鼠標變量

'得到當前鼠標的狀態

DXMouseInputDev.GetDeviceStateMouse DXMouseState

'強制跟蹤不如重新跟蹤

If Err.Number <> 0 Then DXMouseInputDev.Acquire

'如果失敗,退出此過程

If Err.Number <> 0 Then Exit Sub

On Error GoTo 0

'根據HotSpot支持來校准鼠標X坐標

DXMouseX = DXMouseX + DXMouseState.x * MOUSE_SPEED

If DXMouseX < 0 Then DXMouseX = 0

If DXMouseX > 640 - DXMouseHotX Then DXMouseX = 640 - DXMouseHotX

'根據HotSpot支持來校准鼠標Y坐標

DXMouseY = DXMouseY + DXMouseState.y * MOUSE_SPEED

If DXMouseY < 0 Then DXMouseY = 0

If DXMouseY > 480 - DXMouseHotY Then DXMouseY = 480 - DXMouseHotY

'檢測鼠標左鍵狀態

If DXMouseState.buttons(0) <> 0 Then DXLeftMouseButton = True

If DXMouseState.buttons(0) = 0 Then DXLeftMouseButton = False

'檢測鼠標右鍵狀態

If DXMouseState.buttons(1) <> 0 Then DXRightMouseButton = True

If DXMouseState.buttons(1) = 0 Then DXRightMouseButton = False

'如果鼠標的圖標移出表面外,使它不能顯示

'所以,當鼠標靠近邊緣時校准鼠標的位置

If DXMouseX <= 608 Then

Let Mouse_Rect.Right = 32

Else

Let Mouse_Rect.Right = 640 - DXMouseX

End If

If DXMouseY <= 448 Then

Let Mouse_Rect.Bottom = 32

Else

Let Mouse_Rect.Bottom = 480 - DXMouseY

End If

HotSpot_Rect.Left = DXMouseX

HotSpot_Rect.Top = DXMouseY

HotSpot_Rect.Right = DXMouseX + 1

HotSpot_Rect.Bottom = DXMouseY + 1

'如果時機成熟,讓鼠標顯示.

If DXMouseVisible = True Then

DrawMouse

End If

End Sub

在調用此過程前,不要忘了設置DxmouseHotX,DXMouseHotY和DXMouseVisible變量。

Wow,那個代碼很是不少,你會注意到代碼前面的多數部分的一半和Lucky的RefreshMouseState(刷新鼠標狀態)很相似,那一部分僅僅改變了對屏幕大小和Hot Spot的支持,在Lucky的教程的源代碼中,你把你的鼠標指針移出屏幕外(我不是對Lucky的語言攻擊,別搞錯了)。若將DXMouseHotX從屏幕的寬上減去,將DXMouseHotY從屏幕高上減去,你不得不承認你把鼠標移到屏幕外了,當DXMouseHotX正對著屏幕的右邊時,鼠標會停止向右移動,對左邊也是如此。

但是,那僅僅是一部分,我們還是必須“剪”下鼠標指針,否則鼠標指針就不能全部消失,那是為什麼出現了If...Then...Else...的原因。那些代碼會改變Mouse_Rect.Right和Mouse_Rect.Bottom,那時因為當鼠標移出屏幕時會被改變大小,改變 後的Mouse_Rect的Right和Buttom是當時正確的大小。

鼠標被剪了之後,我們若想移動HotSpot_Rect的位置,我們可以改變他的Left,Top,Right和Bottom來實現。

如果你向讓鼠標可見,最後兩行就是檢查鼠標的可見,如果可見,把它畫出來

這是一個小小的過程,而且它使用BltFast來在屏幕上化鼠標,使用正確的剪切方法來剪切Mouse_Rect的大小,我不想太過於詳細的解說怎樣BltFast才算是完成,你最好在Lucky的教程裡找找。

Public Sub DrawMouse()

SurfBack.BltFast DXMouseX, DXMouseY, SurfMain, Mouse_Rect, DDBLTFAST_SRCCOLORKEY Or DDBLTFAST_WAIT

End Sub

SurfBack是我的後備緩存,SurfMain是不可見的表面,SurfMain用來存儲鼠標指針圖片

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