• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            牽著老婆滿街逛

            嚴(yán)以律己,寬以待人. 三思而后行.
            GMail/GTalk: yanglinbo#google.com;
            MSN/Email: tx7do#yahoo.com.cn;
            QQ: 3 0 3 3 9 6 9 2 0 .

            掌握 DirectX 和 DirectInput ——力反饋游戲桿

            原文地址:http://www.microsoft.com/china/MSDN/library/archives/technic/develop/tsother/0314c.asp

            Jason Clark

            ???? 不知不覺中,Windows下的游戲和多媒體程序已經(jīng)開始流行。硬件變得越來(lái)越快,Windows也變得更加靈活。自從Microsoft發(fā)布了DirectX,游戲開發(fā)人員對(duì)其它平臺(tái)已經(jīng)越來(lái)越不感興趣了。許多游戲開發(fā)者也已經(jīng)將他們的開發(fā)工作完全移植到了Windows下。

            ???? PC開發(fā)游戲從來(lái)就沒有輕松過。從無(wú)數(shù)種顯示卡和聲卡中,開發(fā)者學(xué)會(huì)了在功能性和兼容性之間平衡的藝術(shù)。他們不得不處理象頁(yè)面切換、段內(nèi)存結(jié)構(gòu)和位操作這樣令人討厭的問題。并且隨著多人游戲的流行,開發(fā)者必須同時(shí)處理象網(wǎng)絡(luò)和通信等事項(xiàng)。DirectX引入后,游戲開發(fā)者變得輕松了。通過為開發(fā)者提供的DirectX對(duì)象,絕大多數(shù)討厭的工作已經(jīng)被簡(jiǎn)化了。

            ???? 基于DirectX的程序是普通的Windows程序嗎?必須懂得COM嗎?為簡(jiǎn)單的程序值得使用DirectX嗎?必須使用DirectX的全部組件嗎?這樣的問題肯定還有更多。

            ???? 本文將首先介紹DirectX,然后介紹DirectX的一個(gè)組件DirectInput的使用。演示程序說(shuō)明了DirectInput的用法,著重介紹了其強(qiáng)大的反饋功能。

            DirectX揭密

            ???? DirectX是一套為Windows程序提供對(duì)系統(tǒng)硬件更親密控制的組件。(表1列出了DirectX 5.0的組件及其作用)。那么,親密控制是什么意思呢?

            1DirectX 5.0的組件

            組件

            用途

            DirectDraw

            高速2D圖象

            DirectSound

            短響應(yīng)時(shí)間聲音輸出

            Direct3D

            高速3D圖象

            DirectInput

            面向游戲的對(duì)游戲桿和其它輸入設(shè)備的訪問

            DirectSetup

            方便的安裝DirectX組件

            DirectPlay

            面向游戲的通信和網(wǎng)絡(luò)支持

            DirectShow

            視頻流支持

            DirectAnimation

            動(dòng)畫錄放支持

            ???? DirectX提供的硬件控制常常被描述成底層控制,這會(huì)使人聯(lián)想起位操作和其它討厭的事情。實(shí)際上,DirectX組件包含許多高層API,使得象復(fù)制位圖和播放聲音等復(fù)雜的工作變得相當(dāng)簡(jiǎn)單。用“為程序提供比過去更好的對(duì)硬件的控制”來(lái)形容DirectX更準(zhǔn)確。這在Windows中是一個(gè)顯著的特性,因?yàn)樵?span lang="EN-US">Windows中,資源是共享的,并由操作系統(tǒng)控制。

            ???? DirectX組件遵守稱為COM的二進(jìn)制對(duì)象的工業(yè)標(biāo)準(zhǔn)。

            開始DirectX

            ???? 下面從DirectX的安裝開始講起。大多數(shù)情況下,某個(gè)好玩的游戲就會(huì)為系統(tǒng)安裝DirectX。為得到最新的版本,應(yīng)該從最新的Microsoft Platform SDK中將DirectX安裝到系統(tǒng)中。可以在http://www.microsoft.com/msdn站點(diǎn)或者MSDN光盤中找到platform SDK。缺省情況下,Microsoft Platform SDK被安裝到缺省驅(qū)動(dòng)器根目錄下的\MSSDK目錄中。DirectX的頭文件安裝在\MSSDK\INCLUDE目錄中,Lib文件安裝在\MSSDK\LIB目錄中。

            ???? Platform SDK包含了一些非常好的DirectX例子和文檔。早期發(fā)布的DirectX文檔非常粗略而且有些是錯(cuò)誤的,現(xiàn)在的版本已經(jīng)極大地改正了這一問題。最好要熟悉這些文檔。

            ???? 現(xiàn)在已經(jīng)為安裝利用DirectX的程序做好了準(zhǔn)備。所幸的是,不必一次就處理DirectX的全部功能。DirectX是一套可以分別使用的組件。實(shí)際上,在編程概念中,DirectX的不同部分互相沒有聯(lián)系。它們僅僅是具有相同的設(shè)計(jì)風(fēng)格和目標(biāo):使Windows的游戲編程變得容易。

            ???? 使用DirectX組件的程序有什么特殊的地方嗎?根本沒有。使用DirectX組件的程序是基于Win32的程序,它們使用普通Win32 API集,并且可以訪問所有可以獲得的操作系統(tǒng)工具。實(shí)際上,DirectX既可以用于GUI程序,也可以用于控制臺(tái)程序。可以直接用Petzold-style SDK編程開發(fā)程序,也可以用基本類庫(kù),如MFC。總的說(shuō),唯一的要求是大多數(shù)DirectX組件在程序中需要HWND,所以至少要有一個(gè)窗口。

            ???? 雖然DirectX組件是分離的,但是每個(gè)組件的實(shí)現(xiàn)風(fēng)格和使用都是相同的。DirectInput是學(xué)習(xí)DirectX的非常好的出發(fā)點(diǎn),原因是DirectInput是最簡(jiǎn)單的組件之一。

            用力

            ???? 以后在游戲中要“用力”,這是電影《星球大戰(zhàn)》中的說(shuō)法,因?yàn)?span lang="EN-US">DirectInput中加入了相當(dāng)令人陶醉的力反饋支持。DirectX 5.0以前,DirectInput支持從鼠標(biāo)和鍵盤讀取輸入,這是一個(gè)有用但卻令人厭煩的特性。DirectX 5.0中,DirectInput被擴(kuò)充到支持具有以物理力的形式向用戶傳播反饋的能力的設(shè)備。

            ???? 如果不能立即理解上面的內(nèi)容,下面就用一個(gè)游戲進(jìn)行解釋。假設(shè)你剛啟動(dòng)了你最喜歡的超現(xiàn)實(shí)3D越野賽車游戲,正手握力反饋游戲桿。在起跑線上,你可以聽到賽車引擎的空轉(zhuǎn)聲,同時(shí)也能夠通過游戲桿感覺到賽車引擎的空轉(zhuǎn)!比賽開始后,你可以感覺到引擎高速旋轉(zhuǎn)的嗡嗡震動(dòng)。當(dāng)行駛到賽程中崎嶇的地段時(shí),你將會(huì)不停的感覺到電子碰撞。賽車在整個(gè)賽場(chǎng)上撞來(lái)撞去,你的游戲桿也會(huì)如此。賽車車輪卡在車轍中導(dǎo)致賽車被拉向左邊,游戲桿也會(huì)被拉向左邊!整個(gè)過程中你可以感覺到每次顛簸、刮擦、撞擊和撞毀。

            ???? 現(xiàn)在,帶有支持DirectInputWindows驅(qū)動(dòng)程序的唯一的力反饋設(shè)備是MicrosoftSideWinder Force Feedback Pro。這一現(xiàn)狀不會(huì)持續(xù)太久,新設(shè)備以及現(xiàn)有設(shè)備的新驅(qū)動(dòng)程序很快就會(huì)進(jìn)入市場(chǎng)。

            剖析DirectInput

            ???? DirectInput由三個(gè)對(duì)象組成:DirectInput, DirectInputDevice, DirectInputEffect (見表2)DirectInput是一個(gè)高層的對(duì)象,通過DirectInput對(duì)象可以對(duì)相關(guān)的輸入設(shè)備進(jìn)行基本的初始化和查找。DirectInput對(duì)象最終用來(lái)創(chuàng)建低層的DirectInputDevice對(duì)象。DirectX中的每個(gè)主要組件都采用相同的方法,首先創(chuàng)建高層對(duì)象,如DirectInputDirectSound對(duì)象,然后創(chuàng)建低層對(duì)象與硬件進(jìn)行實(shí)際的通信。

            2: DirectInput對(duì)象

            對(duì)象

            說(shuō)明

            DirectInput

            封裝高層DirectInput功能,列舉設(shè)備并用來(lái)創(chuàng)建DirectInputDevice對(duì)象。

            DirectInputDevice

            與物理輸入設(shè)備的接口,例如游戲桿,包括收集和設(shè)置設(shè)備狀態(tài)信息的接口,并且用來(lái)創(chuàng)建DirectInputEffect對(duì)象 (對(duì)于力反饋設(shè)備)

            DirectInputEffect

            封裝能夠在力反饋設(shè)備上“播放”的簡(jiǎn)單效果,提供啟動(dòng)、停止和設(shè)置力反饋效果等功能。

            ???? DirectInput對(duì)象是三個(gè)對(duì)象中最容易理解的。實(shí)際上,它在一個(gè)接口形式IDirectInput (見表3)中只提供五個(gè)函數(shù)。這是DirectInput的一個(gè)非常重要的部分,因?yàn)檫@是出發(fā)點(diǎn)。

            3IdirectInput接口

            成員函數(shù)

            說(shuō)明

            CreateDevice

            創(chuàng)建一個(gè)DirectInputDevice對(duì)象并返回一個(gè)指向其IdirectInputDevice接口的指針。

            EnumDevices

            為找到的與給定標(biāo)準(zhǔn)匹配的每個(gè)設(shè)備調(diào)用一個(gè)回調(diào)函數(shù),每個(gè)回調(diào)函數(shù)提供一個(gè)GUID,可以用在CreateDevice中創(chuàng)建DirectInputDevice對(duì)象。

            GetDeviceStatus

            測(cè)試物理設(shè)備是否連接到系統(tǒng)。

            Initialize

            如果DirectInput對(duì)象是使用CoCreateInstance創(chuàng)建的,那么在使用前必須調(diào)用Initialize成員。如果DirectInput對(duì)象是使用DirectInputCreate創(chuàng)建的,那么就已經(jīng)初始化過了。

            RunControlPanel

            為設(shè)備運(yùn)行Windows Control Panel程序,讓用戶安裝新設(shè)備或者更改已有設(shè)備的配置。游戲桿校準(zhǔn)可以在此處做。

            創(chuàng)建DirectInput對(duì)象

            ???? 為了創(chuàng)建DirectInput對(duì)象并得到其IdirectInput接口指針,應(yīng)該在程序初始化階段使用兩種方法之一完成。

            ???? 第一種方法相當(dāng)簡(jiǎn)單。DirectX提供了一個(gè)助手函數(shù)DirectInputCreate來(lái)創(chuàng)建并初始化DirectInput對(duì)象。它與所有DirectInput的函數(shù)、接口和宏定義都在頭文件DINPUT.H中聲明。實(shí)際的函數(shù)體在DINPUT.LIB文件中。

            DirectInputCreate如下定義:

            HRESULT WINAPI DirectInputCreate(

            ? HINSTANCE hinst,

            ? DWORD dwVersion,

            ? LPDIRECTINPUT * lplpDirectInput,

            ? LPUNKNOWN punkOuter

            );

            ???? 第一個(gè)參數(shù)是應(yīng)用程序的實(shí)例。第二個(gè)參數(shù)是程序需要的DirectInput版本,通常使用DIRECTINPUT_VERSION宏,定義為當(dāng)前版本。第三個(gè)參數(shù)最重要,如果對(duì)COM非常陌生的化就很難理解,它是指向IdirectInput接口的指針的地址。程序中應(yīng)該定義一個(gè)LPDIRECTINPUT類型的變量(可以是全局的)并將其地址作為第三個(gè)參數(shù)傳遞給DirectInputCreate

            ???? 最后一個(gè)參數(shù)叫作punkOuter,與COM技術(shù)中的聚合有關(guān),可以用NULL安全的忽略。返回值是一個(gè)HRESULT,是COM的標(biāo)準(zhǔn)返回類型,可以將返回值與可能的返回值比較,也可以使用COM宏定義SUCCESSFAILED來(lái)檢查。

            ???? 使用DirectInputCreate能夠容易地創(chuàng)建高層對(duì)象并得到其主接口指針。這是DirectX的又一個(gè)設(shè)計(jì)方法,每個(gè)DirectX組件都提供助手函數(shù)來(lái)創(chuàng)建高層對(duì)象,例如DirectInputCreateDirectDrawCreate。在程序中可以用這些助手函數(shù)創(chuàng)建DirectX對(duì)象,然而,這些函數(shù)實(shí)際上創(chuàng)建的是COM對(duì)象。這個(gè)工作也可以用叫作CoCreateInstance的標(biāo)準(zhǔn)Win32 API函數(shù)來(lái)完成。這就引出了創(chuàng)建DirectInput對(duì)象的第二中方法。

            ???? Win32中用CoCreateInstance創(chuàng)建COM對(duì)象非常普遍。如果程序中已經(jīng)使用CoCreateInstance創(chuàng)建了其他COM對(duì)象,開發(fā)者可能就會(huì)希望也用它來(lái)創(chuàng)建DirectX對(duì)象。因?yàn)?span lang="EN-US">COM對(duì)象在安裝時(shí)就在系統(tǒng)中注冊(cè)過,所以唯一需要知道的就是對(duì)象的GUID,用它來(lái)創(chuàng)建一個(gè)實(shí)例。創(chuàng)建DirectX對(duì)象需要的全部GUID都在頭文件中聲明,并在庫(kù)文件DXGUID.LIB中定義。可以將一個(gè)預(yù)定義的GUID傳遞給CoCreateInstance,讓Windows為你創(chuàng)建對(duì)象。

            CoCreateInstance定義如下:

            STDAPI CoCreateInstance(

            ? REFCLSID rclsid,

            ? LPUNKNOWN pUnkOuter,

            ? DWORD dwClsContext,

            ? REFIID riid,

            ? LPVOID * ppv

            );

            ??? ?第一個(gè)參數(shù)是要?jiǎng)?chuàng)建對(duì)象的GUIDDirectX定義的GUID是叫作CLSID_DirectInputGUID結(jié)構(gòu)變量。第二個(gè)參數(shù)是熟悉的pUnkOuter,同樣可以用NULL忽略。第三個(gè)參數(shù)dwClsContext定義COM對(duì)象在何處創(chuàng)建,DirectX只支持進(jìn)程內(nèi)服務(wù)器,所以必須使用CLSCTX_INPROC_SERVER

            ???? 第四個(gè)參數(shù)是兩種方法真正的不同之處。記住COM對(duì)象對(duì)外提供接口,與對(duì)象本身一樣,接口也用GUID識(shí)別。使用第一種方法,不能選擇得到的接口,總是得到IdirectInput。使用CoCreateInstance可以請(qǐng)求對(duì)象所支持的任何接口,方法是使用為接口預(yù)定義的GUID。但是在DirectInput這是沒有意義的,因?yàn)?span lang="EN-US">DirectInput對(duì)象的唯一有用的接口就是IdirectInput。其它DirectX組件支持多個(gè)有用的接口。(例如,DirectDraw對(duì)象可以用IdirectDrawIDirectDraw2接口操作。)

            最后一個(gè)參數(shù)是程序中接口指針變量的實(shí)際地址。

            現(xiàn)在就擁有了對(duì)象和對(duì)象的一個(gè)接口。CoCreateInstance方法還需要另外一步:必須要首先調(diào)用一個(gè)接口函數(shù)初始化對(duì)象。DirectInputCreate提供的是一個(gè)已經(jīng)初始化過的DirectInput對(duì)象,但CoCreateInstance沒有特定于DirectInput的認(rèn)識(shí),因此必須調(diào)用IdirectInput接口的初始化成員函數(shù)。假設(shè)如下定義IdirectInput接口指針變量:

            LPDIRECTINPUT g_lpDI

            ???? 可以如下調(diào)用初始化函數(shù):

            g_lpDI->Initialize( hInstance, DIRECTINPUT_VERSION);

            ???? 既然選擇采取這種標(biāo)準(zhǔn)方法創(chuàng)建對(duì)象,就不得不注意COM需要的其他標(biāo)準(zhǔn),例如需要調(diào)用CoInitializeCoUninitialize

            使用DirectInput對(duì)象

            ???? 一旦擁有了DirectInput對(duì)象,就可以用它來(lái)創(chuàng)建DirectInputDevice對(duì)象,來(lái)管理系統(tǒng)中特定的設(shè)備。創(chuàng)建DirectInputDevice對(duì)象要使用CreateDevice函數(shù),它是作為IdirectInput接口一部分的五個(gè)函數(shù)之一。CreateDevice需要所請(qǐng)求設(shè)備的GUID,返回新DirectInputDevice對(duì)象的IdirectInputDevice接口指針。

            HRESULT CreateDevice(

            ? REFGUID rguid,

            ? LPDIRECTINPUTDEVICE *lplpDirectInputDevice,

            ? LPUNKNOWN pUnkOuter

            );

            ???? 這些內(nèi)容看起來(lái)很熟悉,因?yàn)樗cCoCreateInstanceDirectInputCreate類似。但是,現(xiàn)在還沒有完全準(zhǔn)備好開始DirectInputDevice對(duì)象,原因是在創(chuàng)建DirectInputDevice對(duì)象前需要該設(shè)備的GUID

            ???? DirectInput庫(kù)為創(chuàng)建DirectInputDevice對(duì)象預(yù)定義了兩個(gè)GUIDGUID_SysKeyboardGUID_SysMouse。將兩者之一直接傳遞給CreateDevice函數(shù),就會(huì)得到相應(yīng)設(shè)備的DirectInputDevice對(duì)象。

            ???? 注意,令人感到奇怪的是缺少對(duì)游戲桿的預(yù)定義GUID。在Windows中,通常都有系統(tǒng)鍵盤和系統(tǒng)鼠標(biāo),另一方面,系統(tǒng)本身并不使用游戲桿。可以安裝一個(gè)或者多個(gè)游戲桿,但系統(tǒng)管理的范圍只限于驅(qū)動(dòng)程序級(jí)。系統(tǒng)并為這些設(shè)備指定特殊的系統(tǒng)狀態(tài),也不會(huì)在日常事務(wù)中使用這些設(shè)備。因此,為游戲桿定義GUID對(duì)DirectInput來(lái)說(shuō)是不合理的。

            ???? 那么,如何才能找到與系統(tǒng)連接的游戲桿的GUID呢?要得到它們,必須要列舉設(shè)備。列舉系統(tǒng)設(shè)備和性能在DirectX中相當(dāng)普遍。要列舉系統(tǒng)中的輸入設(shè)備,需要使用EnumDevices函數(shù)。EnumDevicesIdirectInput接口的一部分,如下定義:

            HRESULT EnumDevices(

            ? DWORD dwDevType,

            ? LPDIENUMCALLBACK lpCallback,

            ? LPVOID pvRef,

            ? DWORD dwFlags

            );

            ???? 注意此函數(shù)與Windows中其它列舉API相同,例如EnumWindows。第二個(gè)參數(shù)是一個(gè)回調(diào)函數(shù)。第三個(gè)參數(shù)是程序中定義的32位值。第一個(gè)參數(shù)是想要列舉的設(shè)備類型,對(duì)游戲桿來(lái)說(shuō),是DIDEVTYPE_JOYSTICK(全部的設(shè)備類型列在表4中)。最后一個(gè)參數(shù)是詳細(xì)描述想要列舉的設(shè)備的標(biāo)志。現(xiàn)在支持的標(biāo)志是DIEDFL_ATTACHEDONLYDIEDFL_ALLDEVICES(這兩個(gè)標(biāo)志是互斥獨(dú)占的),此外還有DIEDFL_FORCEFEEDBACK,此標(biāo)志表示力反饋設(shè)備,能夠和另兩個(gè)標(biāo)志位或操作。

            4:定義列舉的輸入設(shè)備

            ???? 以下定義的值可以傳遞給EnumDevices來(lái)選擇列舉哪種類型的輸入設(shè)備。另外也支持子類型,見SDKDIDEVICEINSTANCE結(jié)構(gòu)的文檔。

            說(shuō)明

            DIDEVTYPE_MOUSE

            列舉鼠標(biāo)設(shè)備 (標(biāo)準(zhǔn)、軌跡球等)

            DIDEVTYPE_KEYBOARD

            列舉鍵盤設(shè)備 (標(biāo)準(zhǔn)、鍵區(qū)等)

            DIDEVTYPE_JOYSTICK

            列舉游戲桿設(shè)備 (操縱桿、操縱輪、方向舵等)

            DIDEVTYPE_DEVICE

            列舉其它設(shè)備

            ???? 當(dāng)EnumDevices列舉系統(tǒng)中的輸入設(shè)備時(shí),反復(fù)地調(diào)用回調(diào)函數(shù)。回調(diào)函數(shù)定義如下:

            BOOL CALLBACK EnumProc(LPCDIDEVICEINSTANCE lpddi,LPVOID pvRef) ;

            ???? 因?yàn)榛卣{(diào)函數(shù)是由用戶程序定義并傳遞給EnumDevices的,所以是調(diào)用CreateDevice的最合適地方,直到創(chuàng)建了滿足需要的足夠DirectInputDevice對(duì)象為止。但是回調(diào)函數(shù)并非一定要如此實(shí)現(xiàn),可以簡(jiǎn)單的將列舉設(shè)備的所有GUID保存在一個(gè)表中,在以后的代碼中使用。

            ???? 回調(diào)函數(shù)接受兩個(gè)參數(shù)。第二個(gè)參數(shù)是程序定義的傳遞給EnumDevices32位值。更重要的是,第一個(gè)參數(shù)傳遞指向一個(gè)結(jié)構(gòu)的指針,該結(jié)構(gòu)包含關(guān)于能夠與列舉標(biāo)準(zhǔn)匹配的單個(gè)設(shè)備的許多信息。這是一個(gè)DIDEVICEINSTANCE結(jié)構(gòu)。此結(jié)構(gòu)中最重要的一條信息是設(shè)備的GUID,保存在結(jié)構(gòu)的guidInstance成員中。

            ???? 當(dāng)程序中完全完成DirectInput有關(guān)的工作后,就應(yīng)該調(diào)用IdirectInput接口的Release成員。這就告訴DirectInput對(duì)象可以釋放自己了。在DirectX中,最好養(yǎng)成釋放對(duì)象的習(xí)慣,從低層對(duì)象開始,到高層對(duì)象結(jié)束。正常情況下程序會(huì)作為清除或者關(guān)閉的例行公事的一部分調(diào)用Release。這是使用每個(gè)DirectX組件的必要步驟,也是使用每個(gè)COM組件的必要步驟。

            ???? 現(xiàn)在已經(jīng)用CreateDevice成員函數(shù)獲得了DirectInputDevice對(duì)象的一個(gè)接口,為開始處理與系統(tǒng)連接的實(shí)際物理設(shè)備做好了準(zhǔn)備。

            使用DirectInputDevice對(duì)象

            ???? DirectInputDevice對(duì)象的每個(gè)實(shí)例都與系統(tǒng)中的特定設(shè)備相關(guān)。此對(duì)象提供了對(duì)系統(tǒng)硬件更多的控制和能力,從而使DirectX的允諾實(shí)現(xiàn)。下面討論擁有了DirectInputDevice對(duì)象后下一步干什么。

            ???? 擁有了IdirectInputDevice接口的一個(gè)接口指針,現(xiàn)在干什么?首先,設(shè)置設(shè)備的數(shù)據(jù)格式。通過調(diào)用SetDataFormat來(lái)完成,該函數(shù)是一個(gè)接口成員函數(shù)。設(shè)置數(shù)據(jù)格式包括無(wú)數(shù)可能的決定,包括軸信息、相對(duì)或絕對(duì)坐標(biāo)信息、等等。所有這些細(xì)節(jié)通過一個(gè)叫作DIDATAFORMAT的結(jié)構(gòu)傳遞給此函數(shù)。實(shí)際上,SetDataFormat唯一的參數(shù)就是指向此結(jié)構(gòu)的指針。

            ???? 填寫這個(gè)結(jié)構(gòu)的細(xì)節(jié)會(huì)使人發(fā)憷。值得感謝的是這一工作并不是必須的,因?yàn)?span lang="EN-US">DirectInput已經(jīng)定義了幾個(gè)DIDATAFORMAT結(jié)構(gòu)變量,可以用于比較普通的輸入設(shè)備:c_dfDIKeyboard, c_dfDIMouse, c_dfDIJoystick, c_dfDIJoystick2。為普通的力反饋游戲桿設(shè)置數(shù)據(jù)格式,可以使用下面的調(diào)用形式:

            lpdid->SetDataFormat( &c_dfDIJoystick ) ;

            ???? 在此例中,lpdid是指向IdirectInputDevice接口的指針。

            ???? 設(shè)置完設(shè)備對(duì)象的數(shù)據(jù)格式后,就需要設(shè)置設(shè)備的協(xié)作級(jí)別。因?yàn)閰f(xié)作級(jí)別在整個(gè)DirectX中很常見,所以這里要做一下說(shuō)明。大多數(shù)直接處理系統(tǒng)硬件的DirectX對(duì)象在接口的成員中都有一個(gè)叫作SetCooperativeLevel函數(shù)。這個(gè)函數(shù)很重要,因?yàn)樗x了程序操縱與系統(tǒng)中其它進(jìn)程有關(guān)的硬件的控制級(jí)別。同其它DirectX對(duì)象一樣,只有設(shè)置了協(xié)作級(jí)別才能使DirectInputDevice對(duì)象工作。要理解協(xié)作級(jí)別,就需要熟悉Acquire函數(shù)。調(diào)用此函數(shù)是為了獲得對(duì)物理設(shè)備的實(shí)際訪問(不要和邏輯上的DirectInputDevice對(duì)象混了)。相反的,Unacquire函數(shù)釋放對(duì)物理設(shè)備的訪問。

            ???? 下面是函數(shù)SetCooperativeLevel的定義:

            HRESULT SetCooperativeLevel(

            ? HWND hwnd,????

            ? DWORD dwFlags?

            );

            ???? hwnd是程序的主窗口。標(biāo)志是下面一些值的或操作的結(jié)合: DISCL_BACKGROUND, DISCL_FOREGROUND, DISCL_EXCLUSIVE, DISCL_ NONEXCLUSIVE

            ???? 如果標(biāo)志參數(shù)中或上了DISCL_EXCLUSIVE,則當(dāng)獲得設(shè)備后本程序就成為唯一允許訪問該物理設(shè)備的進(jìn)程。另一方面,如果選擇了DISCL_NONEXCLUSIVE,那么系統(tǒng)中可以有多個(gè)進(jìn)程同時(shí)協(xié)作獲得和使用該設(shè)備。如果或上了DISCL_BACKGROUND,程序?qū)⒉粫?huì)失去物理設(shè)備。然而,象Ctrl+Alt+Del組合鍵被按下這樣的系統(tǒng)事件仍然能夠隱含地“unacquire”程序中的設(shè)備。如果使用了DISCL_ FOREGROUND,當(dāng)不是活動(dòng)窗口時(shí),程序?qū)?huì)自動(dòng)釋放物理設(shè)備。這就是將程序主窗口句柄傳遞給SetCooperativeLevel的意義。DirectX根據(jù)窗口是否是系統(tǒng)當(dāng)前活動(dòng)窗口自動(dòng)調(diào)整設(shè)備共享。

            ???? 那么所有這些值的意義是什么呢?下面舉個(gè)例子說(shuō)明。如果力反饋游戲桿的協(xié)作模式是DISCL_FOREGROUND | DISCL_EXCLUSIVE,那么只要程序處于活動(dòng)狀態(tài),就能夠從游戲桿讀數(shù)據(jù)并播放力反饋效果(力反饋需要exclusive-level協(xié)作)。只要用戶一選擇其它程序,程序就失去對(duì)物理設(shè)備的控制,新激活的程序就能夠訪問該設(shè)備。這意味著在調(diào)試程序時(shí),如果切換到調(diào)試器窗口,程序就會(huì)因?yàn)榇翱谧優(yōu)榉腔顒?dòng)的而失去對(duì)游戲桿的控制。

            ???? 如果將同一游戲桿的協(xié)作級(jí)別設(shè)為DISCL_BACKGROUND | DISCL_EXCLUSIVE將會(huì)是什么情況呢?程序?qū)?huì)所有時(shí)間都能訪問游戲桿,不管窗口的狀態(tài)。但是現(xiàn)在系統(tǒng)中其它進(jìn)程就不能獲得游戲桿,除非程序釋放了游戲桿,不管用戶在做什么!

            ??? 非常明顯,在正式發(fā)布的產(chǎn)品中應(yīng)該使用DISCL_FOREGROUND | DISCL_EXCLUSIVE,而在調(diào)試版本中應(yīng)該使用DISCL_BACKGROUND|DISCL_EXCLUSIVE。但是也不總是這樣選擇。例如,如果設(shè)備是系統(tǒng)鍵盤,那么DirectInputDevice想獨(dú)占使用而調(diào)用SetCooperativeLevel將會(huì)失敗。這是因?yàn)椴僮飨到y(tǒng)想要允許用戶自由地從一個(gè)程序切換到另一個(gè)程序。類似的,DirectInputDevice不會(huì)允許以協(xié)作級(jí)別DISCL_BACKGROUND|DISCL_EXCLUSIVE請(qǐng)求系統(tǒng)鼠標(biāo)。Windows不希望一個(gè)程序能夠完全將用戶與操作系統(tǒng)的聯(lián)系切斷。

            ???? 在能夠從物理設(shè)備讀取信息或向物理設(shè)備發(fā)送信息之前,必須要用Acquire獲得設(shè)備。在臨時(shí)或永久結(jié)束設(shè)備使用時(shí)要明確地使用Unacquire函數(shù)釋放設(shè)備。但Unacquire并不是失去設(shè)備控制的唯一方法。

            ???? 如果設(shè)置協(xié)作級(jí)別時(shí)使用DISCL_FOREGROUND標(biāo)志,那么程序的主窗口不再是系統(tǒng)中的活動(dòng)窗口時(shí)設(shè)備將被明確釋放。這就是說(shuō),在程序調(diào)用Acquire和實(shí)際試圖從設(shè)備讀取信息之間,能夠失去對(duì)設(shè)備的占有。所以需要檢查返回值來(lái)捕捉這樣的錯(cuò)誤,并準(zhǔn)備好在任何時(shí)間重新獲得該設(shè)備。

            ???? 關(guān)于AcquireUnacquire的決定性要點(diǎn):當(dāng)程序獲得獨(dú)占協(xié)作級(jí)別的設(shè)備時(shí),DirectX擁有該設(shè)備。例如,如果鼠標(biāo)被DirectX(獨(dú)占)獲得,那么程序窗口中的按鈕就不會(huì)對(duì)鼠標(biāo)做出響應(yīng)。這就是說(shuō),如果想讓Windows對(duì)設(shè)備響應(yīng),就應(yīng)該釋放該設(shè)備。換句話說(shuō),如果不想讓DirectInput從設(shè)備中讀取數(shù)據(jù),就調(diào)用Unacquire

            ???? 設(shè)置完設(shè)備的協(xié)作級(jí)別后,接著應(yīng)該為設(shè)備配置其它設(shè)置。獲得了設(shè)備后,接著就應(yīng)該開始使用GetDeviceState函數(shù)輪流檢測(cè)輸入的數(shù)據(jù)。當(dāng)完成與設(shè)備對(duì)象的操作后,調(diào)用Unacquire釋放DirectInputDevice對(duì)象。設(shè)備與設(shè)備之間存在細(xì)節(jié)上的差別;下面講解游戲桿和鍵盤,應(yīng)該能為從其它設(shè)備讀取輸入提供足夠的基礎(chǔ)知識(shí)。

            鍵盤

            ???? 鍵盤是到目前為止最容易讀取的設(shè)備。實(shí)際上,設(shè)置完數(shù)據(jù)格式、協(xié)作級(jí)別、獲得設(shè)備以后,就可以讀取鍵盤狀態(tài)了。讀取鍵盤狀態(tài)要使用IdirectInputDevice接口的GetDeviceState成員。GetDeviceState用關(guān)于物理設(shè)備的狀態(tài)信息組裝一個(gè)結(jié)構(gòu),所組裝結(jié)構(gòu)的類型由前面對(duì)SetDataFormat的調(diào)用決定。對(duì)鍵盤來(lái)說(shuō),此數(shù)據(jù)結(jié)構(gòu)是一個(gè)簡(jiǎn)單的256個(gè)字節(jié)組成的數(shù)組。每個(gè)字節(jié)對(duì)應(yīng)于鍵盤上的一個(gè)鍵,如果某個(gè)鍵按下,相應(yīng)字節(jié)的高位就被設(shè)置。

            ???? DirectInput定義了一套以DIK_XXX為前綴的常量,這些常量可以用來(lái)索引字節(jié)數(shù)組以找到關(guān)于特定鍵的數(shù)據(jù)。例如,如果要檢查右Shif鍵當(dāng)前是否按下,可以使用DIK_RSHIFT定義:

            GetDeviceState(256,(LPVOID) cKeyboardData) ;

            if(cKeyboardData[DIK_ RSHIFT]&0x80)

            ??? DoWhatever() ;

            ???? CKeyboardData256個(gè)字節(jié)的緩沖區(qū)。幾乎就是這么簡(jiǎn)單,但是要記住,不管GetDeviceState在何時(shí)返回DIERR_INPUTLOST,就必須使用Acquire獲得設(shè)備。這種情況發(fā)生在每次用戶從程序切換離開的時(shí)候。

            ???? 還有一點(diǎn)很重要,就是能夠請(qǐng)求DirectInput緩沖鍵盤信息。這要求提供一個(gè)緩沖區(qū)并使用SetProperty為設(shè)備設(shè)置緩沖區(qū)大小。在本文中沒有篇幅討論這一技術(shù),但這一技術(shù)在程序不能相當(dāng)頻繁的檢查鍵盤狀態(tài)時(shí)非常有用。用戶有可能在程序中兩次GetDeviceState調(diào)用之間按下又松開了一個(gè)鍵,如果DirectInput不緩沖鍵盤數(shù)據(jù)的化,這種擊鍵動(dòng)作就丟失了。

            游戲桿

            ??? 游戲桿非常好玩。與其好聽的名稱(Joystick——原意為歡樂桿)相符,這種設(shè)備為游戲體驗(yàn)添加了許多樂趣,同時(shí)也為程序員的體驗(yàn)添加了一些東西。正常情況下,通過調(diào)用IdirectInput接口的CreateDevice成員得到IdirectInputDevice接口(和對(duì)象),這對(duì)游戲桿也適用。

            ??? ?但是開發(fā)人員都希望立即將接口升級(jí)到IDirectInputDevice2,那么可以象下面這樣使用QueryInterface調(diào)用請(qǐng)求CreateDevice返回新的接口:

            hr = lpDIDeviceJoystickTemp->QueryInterface(???? IID_IDirectInputDevice2,

            ??? (void **) &g_lpDIDeviceJoystick);

            ???? 如果成功,就可以釋放原來(lái)的接口,開始使用漂亮的新IDirectInputDevice2接口。但是為什么要這么做呢?IDirectInputDevice2接口提供IdirectInputDevice的所有功能,而且還有另外兩個(gè)重要特性:支持查詢?cè)O(shè)備和支持力反饋設(shè)備。

            ???? 其次,需要設(shè)置上的一些考慮。還記得SetDataFormat定義了GetDeviceState返回的數(shù)據(jù)的類型。對(duì)于游戲桿設(shè)備,使用c_dfDIJoystickc_dfDIJoystick2兩個(gè)預(yù)定義變量之一,將返回?cái)?shù)據(jù)的類型設(shè)置為DIJOYSTATEDIJOYSTATE2結(jié)構(gòu)。選擇哪種主要取決于要使用游戲桿哪種類型的特性。瀏覽這些結(jié)構(gòu)中的成員應(yīng)該對(duì)弄清這個(gè)問題有幫助。

            ???? 同所有輸入設(shè)備一樣,要為游戲桿設(shè)置數(shù)據(jù)格式和協(xié)作級(jí)別。游戲桿往往比鍵盤需要更多一點(diǎn)注意。這是因?yàn)楝F(xiàn)在還幾乎沒有功能完美的游戲桿,所以程序應(yīng)該檢查以確保控制的設(shè)備能滿足要求。如果不能,就調(diào)整要求或者提醒用戶游戲桿太落后!設(shè)備的能力可以并且應(yīng)該調(diào)用IdirectInputDevice接口的成員函數(shù)GetCapabilities探測(cè)。

            ???? 這就引出了適用于所有DirectX組件的另一個(gè)討論點(diǎn)。DirectX為多種設(shè)備提供廣泛的支持。軟件開發(fā)環(huán)境和使用環(huán)境可能有很大差別,不同的計(jì)算機(jī)支持不同水平的DirectX功能。編寫好使用DirectX的軟件,需要檢查硬件的能力。最差的情況下,如果某個(gè)功能不支持,可以退出程序。最好的情況當(dāng)然是程序能夠聰明地根據(jù)缺少的特性調(diào)整本身的需求。

            ???? 在開始從設(shè)備得到輸入之前,需要設(shè)置設(shè)備的特性。這些特性包括象返回值的范圍、游戲桿的中心點(diǎn)等此類的細(xì)節(jié)。這一工作由函數(shù)SetProperty完成,相當(dāng)復(fù)雜。

            ???? SetProperty設(shè)置設(shè)備的一個(gè)特性。首先,必須使用關(guān)于要改變的設(shè)置的一些信息填寫一個(gè)數(shù)據(jù)結(jié)構(gòu)。請(qǐng)參考Platform SDK中的文檔,得到所有數(shù)據(jù)結(jié)構(gòu)。每個(gè)結(jié)構(gòu)都以一個(gè)DIPROPHEADER結(jié)構(gòu)開始,此結(jié)構(gòu)中填寫描述要改變的設(shè)置的信息。然后,用特定于所改變的設(shè)置的數(shù)據(jù)填寫結(jié)構(gòu)中剩余的部分。最后,調(diào)用SetProperty,參數(shù)是GUID和指向結(jié)構(gòu)中DIPROPHEADER部分的指針。下面的代碼片段將游戲桿的垂直范圍設(shè)置為–100100

            DIPROPRANGE? dipRange ;

            dipRange.diph.dwSize?????? = sizeof(dipRange);

            dipRange.diph.dwHeaderSize = sizeof(dipRange.diph);

            dipRange.diph.dwObj??????? = DIJOFS_Y;

            dipRange.diph.dwHow??????? = DIPH_BYOFFSET;

            dipRange.lMin????????????? = -100;

            dipRange.lMax????????????? = +100;

            g_lpDIDeviceJoystick->SetProperty( DIPROP_RANGE,?????? ????????????????????????????????? &dipRange.diph) ;

            ???? 此結(jié)構(gòu)中最難懂的部分是diph.dwObjdiph.dwHowdiph.dwHow描述diph.dwObj中保存何種信息。diph.dwObj實(shí)際描述哪個(gè)屬性被設(shè)置。大多數(shù)情況下,diph.dwHow的值是DIPH_BYOFFSETdiph.dwObj的值是傳遞給SetDataFormat的結(jié)構(gòu)中一個(gè)預(yù)定義的偏移。

            ???? 應(yīng)該指出能夠列舉設(shè)備的對(duì)象,包括按鈕和其它特點(diǎn)。這一工作由EnumObjects函數(shù)完成。這樣做時(shí),應(yīng)該提供一個(gè)對(duì)象標(biāo)志符。將此標(biāo)志符傳遞給diph.dwObj成員,將diph.dwHow成員填寫為DIPH_BYID

            ???? 在從設(shè)備讀取數(shù)據(jù)之前,至少要為設(shè)備的XY坐標(biāo)軸設(shè)置最小和最大值。設(shè)置好設(shè)備屬性后,就可以獲得設(shè)備并開始從設(shè)備獲得數(shù)據(jù)。從游戲桿獲取數(shù)據(jù)與從鍵盤或鼠標(biāo)獲取數(shù)據(jù)不同,因?yàn)橛螒驐U是查詢?cè)O(shè)備。

            ???? 鍵盤和鼠標(biāo)會(huì)引發(fā)硬件中斷,由系統(tǒng)中的驅(qū)動(dòng)程序處理,并用來(lái)更新通過調(diào)用GetDeviceStateDirectInput返回的數(shù)據(jù)。查詢?cè)O(shè)備(如大多數(shù)游戲桿)不產(chǎn)生硬件中斷,因此,DirectInput必須被告知從設(shè)備獲取狀態(tài)信息。這一工作通過調(diào)用IDirectInputDevice2接口的Poll成員函數(shù)完成。此時(shí)也是檢查???? 設(shè)備是否需要重新獲得的適當(dāng)時(shí)機(jī)。設(shè)備被成功查詢后,就可以調(diào)用GetDeviceState獲取狀態(tài)信息。

            ???? 如果調(diào)用SetDataFormat時(shí)使用c_dfDIJoystick變量,那么GetDeviceState將用游戲桿當(dāng)前的狀態(tài)信息填充一個(gè)DIJOYSTATE結(jié)構(gòu)。此結(jié)構(gòu)的內(nèi)容主要取決于物理設(shè)備的特性和SetProperty的設(shè)置。例如,如果結(jié)構(gòu)中的lY成員等于-50,并且Y軸的范圍設(shè)置為-100100,那么就是說(shuō)游戲桿在垂直方向上處于中心和最頂端的中間。程序中應(yīng)該確保設(shè)備的范圍設(shè)置為能合理滿足需求的值。為了從游戲桿設(shè)備中獲取數(shù)據(jù),程序應(yīng)該定期查詢?cè)O(shè)備。

            使用DirectInputEffect

            ??? 首先,應(yīng)該解釋一些力反饋技術(shù)。力反饋設(shè)備是能夠產(chǎn)生用戶可以感覺到的力的設(shè)備,這些力叫作效果,例如顛簸效果或者持續(xù)的將操縱桿推向右上方的力。這些效果是“播放”出來(lái)的,效果由程序控制播放,或者對(duì)函數(shù)調(diào)用響應(yīng),或者對(duì)用戶按鍵自動(dòng)反應(yīng)。

            ???? DirectInput目前支持大約一打不同的效果類型(見表5)。這些效果的范圍從完全由程序控制的低級(jí)持續(xù)力效果,到由DirectInput或設(shè)備自己控制的高級(jí)傾斜或波動(dòng)效果。效果有四種基本類型:持續(xù)力、傾斜效果、周期效果和條件。持續(xù)力是單一方向上不改變強(qiáng)度的力。傾斜效果是強(qiáng)度隨時(shí)間線性變化的持續(xù)的力。周期效果是沿著給定的軸重復(fù)變化,其量級(jí)或者力的強(qiáng)度由周期效果定義。條件是對(duì)用戶與游戲桿的交互作用做出響應(yīng)的效果。這種效果可能是象一根彈簧,操縱桿向某個(gè)方向推得越遠(yuǎn),反彈力就越強(qiáng)。

            5DirectInput效果的類型

            GUID

            說(shuō)明

            使用方法注解

            GUID_ConstantForce

            固定強(qiáng)度、特定方向的持續(xù)拉力。

            使用DICONSTANT力結(jié)構(gòu)作為DIEFFECT結(jié)構(gòu)的一部分實(shí)現(xiàn)持續(xù)力。

            GUID_CustomForce

            一序列持續(xù)力下傳到設(shè)備,按順序播放。

            DICUSTOMFORCE結(jié)構(gòu)被用來(lái)定義力。

            GUID_Damper

            隨沿坐標(biāo)軸的移動(dòng)增加的條件效果。

            實(shí)現(xiàn)這種效果的特定類型結(jié)構(gòu)是DICONDITION結(jié)構(gòu)。條件效果通常不支持包。

            GUID_Friction

            阻礙沿坐標(biāo)軸移動(dòng)的條件效果。

            實(shí)現(xiàn)這種效果的特定類型結(jié)構(gòu)是DICONDITION結(jié)構(gòu)。條件效果通常不支持包。

            GUID_Inertia

            隨沿坐標(biāo)軸移動(dòng)的加速度增加的條件效果。

            實(shí)現(xiàn)這種效果的特定類型結(jié)構(gòu)是DICONDITION結(jié)構(gòu)。條件效果通常不支持包。

            GUID_RampForce

            特定方向上大小線性增加或減小的拉力。

            DIRAMPFORCE結(jié)構(gòu)被用來(lái)作為DIEFFECT結(jié)構(gòu)中的類型相關(guān)部分。

            GUID_SawtoothDown

            力瞬間達(dá)到最大然后線性減小到最小的周期效果。

            需要的特定類型結(jié)構(gòu)是DIPERIODIC結(jié)構(gòu)。

            GUID_SawtoothUp

            力從最小線性增加到最大然后瞬間降到最小的周期效果

            需要的特定類型結(jié)構(gòu)是DIPERIODIC結(jié)構(gòu)。

            GUID_Sine

            力正弦變化的周期效果。

            需要的特定類型結(jié)構(gòu)是DIPERIODIC結(jié)構(gòu)。

            GUID_Spring

            力隨到某個(gè)中點(diǎn)的相對(duì)距離而增大的條件效果。

            實(shí)現(xiàn)這種效果的特定類型結(jié)構(gòu)是DICONDITION結(jié)構(gòu)。條件效果通常不支持包。

            GUID_Square

            力瞬時(shí)在最大與最小之間轉(zhuǎn)變的周期效果。

            需要的特定類型結(jié)構(gòu)是DIPERIODIC結(jié)構(gòu)。

            GUID_Triangle

            力在最大與最小之間線性變化的周期效果。

            需要的特定類型結(jié)構(gòu)是DIPERIODIC結(jié)構(gòu)。

            ???? 下面所有與力反饋游戲桿有關(guān)的工作都是針對(duì)Microsoft SideWinder Force Feedback Pro游戲桿,這就是說(shuō),本文中的某些細(xì)節(jié)對(duì)其它設(shè)備可能多少會(huì)產(chǎn)生一些問題。

            ???? 在創(chuàng)建力反饋效果以前先獲得設(shè)備是一個(gè)不錯(cuò)的想法。雖然這不是必須的,但是在效果能夠被下傳到設(shè)備前必須要獲得設(shè)備。這一點(diǎn)對(duì)于播放對(duì)用戶按下按鈕做出反應(yīng)的力效果尤其重要。

            ???? 要?jiǎng)?chuàng)建效果,首先要為每個(gè)打算使用的效果創(chuàng)建DirectInputEffect對(duì)象的實(shí)例。這一工作通過調(diào)用IDirectInputDevice2接口的CreateEffect成員函數(shù)完成。此函數(shù)需要效果的GUID,以及指向DIEFFECT結(jié)構(gòu)的指針,該結(jié)構(gòu)中填寫的是效果的細(xì)節(jié)。最后,CreateEffect返回一個(gè)指向IdirectInputEffect接口的指針,該指針的地址是CreateEffect的一個(gè)參數(shù)。這個(gè)調(diào)用的核心部分集中在DIEFFECT結(jié)構(gòu)的填充。

            ???? DIEFFECT結(jié)構(gòu)如下定義:

            typedef struct {

            ??? DWORD dwSize;

            ??? DWORD dwFlags;

            ??? DWORD dwDuration;

            ??? DWORD dwSamplePeriod;

            ??? DWORD dwGain;

            ??? DWORD dwTriggerButton;

            ??? DWORD dwTriggerRepeatInterval;

            ??? DWORD cAxes;

            ??? LPDWORD rgdwAxes;

            ??? LPLONG rglDirection;

            ??? LPDIENVELOPE lpEnvelope;

            ??? DWORD cbTypeSpecificParams;

            ??? LPVOID lpvTypeSpecificParams;

            } DIEFFECT, *LPDIEFFECT;

            dwSize成員是此結(jié)構(gòu)的字節(jié)數(shù)。DwFlags指出效果使用的坐標(biāo)類型,以及是使用偏移方法還是ID方法描述按鈕(就向前面說(shuō)明的SetProperty)。通常情況下,可以設(shè)置為DIEFF_CARTESIAN|DIEFF_OBJECTOFFSETS,即按鈕采用偏移描述,坐標(biāo)使用XYZ坐標(biāo)形式。

            DwDuration說(shuō)明效果播放多少毫秒。注意dwDuration可以設(shè)為INFINITEDwSamplePeriod說(shuō)明效果播放一個(gè)周期花費(fèi)多少毫秒。不同設(shè)備支持不同的周期。實(shí)際中,SideWinder游戲桿支持的周期不大于1秒,不小于1/80秒。DwGain可以看作效果的主要量,因?yàn)樗f(shuō)明效果多么有力。此值的范圍是010000

            DwTriggerButtondwTriggerRepeatInterval用來(lái)設(shè)置觸發(fā)效果播放的按鈕,以及重復(fù)頻率。當(dāng)然,可以通過將dwTriggerButton的值設(shè)置為DIEB_NOTRIGGER來(lái)將效果設(shè)置為與按鈕無(wú)關(guān)。否則,dwFlags定義通過ID還是偏移方式描述按鈕。因?yàn)槠品绞讲恍枰{(diào)用EnumObjects,所以一般可以將值指定為DIJOFS_ BUTTON0DIJOFS_BUTTON1

            CAxes成員說(shuō)明效果將影響幾個(gè)軸。RgdwAxes指向一個(gè)描述所包含的軸的DWORD數(shù)組,數(shù)組中每個(gè)軸是一個(gè)成員。同按鈕一樣,軸也是用偏移或者ID來(lái)指明。一般的偏移值包括DIJOFS_XDIJOFS_Y

            ???? 同樣,rglDirection成員指向一個(gè)long型數(shù)組,每個(gè)軸是一個(gè)成員。在笛卡兒坐標(biāo)中,(Y=-1X=1)與(Y=-10X=10)描述的是同一個(gè)方向。這就是說(shuō),如果想得到一個(gè)不是45度整數(shù)倍方向上的斜的力,就應(yīng)該調(diào)整兩個(gè)值的相對(duì)大小。例如,(Y=-10X=1)描述與上面例子在同一象限的方向,但卻明顯靠近Y軸。

            ???? 效果也可以有描述它們的包。填充一個(gè)DIENVELOPE結(jié)構(gòu),并將其地址填寫到lpEnvelope成員就可以完成。包可以在一段時(shí)間內(nèi)影響效果的數(shù)量或力量。其中,起動(dòng)水平是效果的開始變化點(diǎn),啟動(dòng)時(shí)間說(shuō)明效果達(dá)到力量保持階段花費(fèi)多少毫秒。衰減水平是效果在包最后達(dá)到的水平,衰減時(shí)間是衰減用掉了多少豪秒。包可以用來(lái)制造初始狀態(tài)較強(qiáng),然后慢慢衰減的力效果。圖1中描繪了包如何改變效果。

            1:包效果

            ???? DIEFFECT結(jié)構(gòu)的最后兩個(gè)成員是cbTypeSpecificParamslpvTypeSpecificParams。它們保存特定于所創(chuàng)建效果類型的結(jié)構(gòu)的字節(jié)數(shù)和地址。特定類型的效果使用何種結(jié)構(gòu)的信息見表5

            ???? 填寫完這個(gè)結(jié)構(gòu)并調(diào)用CreateEffect后,就會(huì)獲得指向IdirectInputEffect接口的指針,現(xiàn)在可以使用此接口播放效果,改變效果等。如果沒有將效果聯(lián)系到按鈕,就必須用IdirectInputEffect接口的StartStop成員播放和停止效果。如果效果與按鈕關(guān)聯(lián),那么在創(chuàng)建時(shí)下傳到設(shè)備;否則,效果在播放時(shí)自動(dòng)下傳到設(shè)備。如果程序必須重新獲得設(shè)備,那么所有與按鈕相關(guān)的效果必須通過明確的調(diào)用Download成員才能下傳到設(shè)備。

            ???? 效果能夠用Unload成員卸載,也能夠通過向SetParameters成員函數(shù)傳遞新的DIEFFECT結(jié)構(gòu)重新設(shè)置參數(shù)。當(dāng)程序用完效果后,必須調(diào)用接口的Release成員。

            演示例子

            ??

            2:演示程序

            ???? 首先,應(yīng)該建立演示代碼并運(yùn)行,應(yīng)該能看到一個(gè)游戲桿配置窗口(見圖2)。使用游戲桿可以移動(dòng)中間的人,在窗口的左上角是坐標(biāo)和輸入狀態(tài)信息。如果有力反饋游戲桿,那么通過按下按鈕12應(yīng)該能感覺到一對(duì)不同的力。如果將小人撞到窗口的邊緣,應(yīng)該能感到碰撞效果。

            ???? 這個(gè)例子說(shuō)明了DirectInput的使用。這里仍然有相當(dāng)數(shù)量的代碼與DirectInput沒有直接關(guān)系。這些代碼根據(jù)功能劃分成模塊。Main.cpp是基本的WinMain樣板文件和窗口創(chuàng)建代碼。除了調(diào)用初始化函數(shù)外,這部分代碼基本上與本文的其它部分沒有關(guān)系。它創(chuàng)建窗口,進(jìn)入消息循環(huán)。WndProc.cpp包含程序窗口的窗口過程。

            ???? Demo.cpp開始了有意義的代碼。不論何時(shí)提到“demo”,都是指程序游戲。例如,InitDemo函數(shù)為圖形設(shè)置狀態(tài)數(shù)據(jù)并創(chuàng)建一些所需的時(shí)間和線程。除了初始化,此演示程序運(yùn)行在第二個(gè)線程中。該線程嘗試讀取輸入并刷新狀態(tài)數(shù)據(jù),每秒進(jìn)行32次。然后使窗口無(wú)效,從而讓主線程重新繪制窗口。這就是說(shuō),輸入和狀態(tài)變化的一個(gè)反復(fù),或者說(shuō)一個(gè)演示周期,大約有1/32秒。所以,不管顯示刷新得多么頻繁,輸入響應(yīng)速度都會(huì)保持一致。

            ???? DX.cpp包含DirectX需要的非常小的初始化和結(jié)束處理,然后調(diào)用完成特殊DirectInput工作的函數(shù)。除了CoInitializeCoUninitialize外,DXInput模塊包含本文中提到的所有內(nèi)容。函數(shù)按照演示程序中用到的順序列出,每個(gè)只列一次。注意,DirectInput的大部分工作在初始化中完成。冗長(zhǎng)的任務(wù)劃分成幾個(gè)函數(shù)列在表6中。

            6DXInput.cpp的函數(shù)

            成員函數(shù)

            說(shuō)明

            InitDirectInput

            為系統(tǒng)鍵盤初始化DirectInput對(duì)象和DirectInputDevice對(duì)象。

            EnumJoy

            列舉設(shè)備的回調(diào)函數(shù)。此函數(shù)為系統(tǒng)中安裝的第一個(gè)游戲桿創(chuàng)建DirectInputDevice

            InitForceFeedback

            如果找到游戲桿是適應(yīng)力反饋的,此函數(shù)就為力反饋效果進(jìn)行一些設(shè)置。

            InitRampEffect, InitBumpEffects, InitWavyEffect

            這些函數(shù)每個(gè)都設(shè)置一個(gè)效果。這些效果演示了DirectInput中幾種不同的效果,并且應(yīng)該對(duì)創(chuàng)建新效果有用。

            ???? 這個(gè)模塊中的另一個(gè)要點(diǎn)是演示程序重復(fù)調(diào)用的函數(shù)。ForceEffect播放一個(gè)存在的效果,GetKeyboardInput獲得鍵盤輸入,GetJoystickInput獲得游戲桿輸入。最后UnInitDirectInput結(jié)束所有的一切。

            ???? 要獲得完整的源代碼,請(qǐng)?jiān)L問MSJWeb站點(diǎn)http://www.microsoft.com/msj.

            posted on 2006-06-20 15:27 楊粼波 閱讀(1307) 評(píng)論(0)  編輯 收藏 引用 所屬分類: 文章收藏

            久久婷婷午色综合夜啪| 91久久精品国产免费直播| 欧美日韩成人精品久久久免费看| 国产91色综合久久免费| 欧美亚洲色综久久精品国产| 伊人久久大香线蕉亚洲五月天| 日本WV一本一道久久香蕉| 亚洲午夜无码AV毛片久久| 久久中文字幕视频、最近更新| 国产精品免费看久久久香蕉| 国产精品伦理久久久久久| 国产精品日韩欧美久久综合| 色综合久久中文色婷婷| 亚洲综合久久综合激情久久| 91久久国产视频| 狠狠色综合久久久久尤物| 久久AAAA片一区二区| 精品久久久久久99人妻| 久久人搡人人玩人妻精品首页| 久久九色综合九色99伊人| 青春久久| 亚洲午夜久久久久妓女影院| 日日躁夜夜躁狠狠久久AV| 99久久er这里只有精品18| 免费国产99久久久香蕉| 久久精品国产亚洲一区二区三区 | 国内精品人妻无码久久久影院导航 | 开心久久婷婷综合中文字幕| 久久久精品人妻无码专区不卡| 久久亚洲2019中文字幕| 2020国产成人久久精品| 色婷婷综合久久久中文字幕| 国产精品美女久久久| 精品久久久无码中文字幕| 午夜精品久久久久久影视riav| 无码专区久久综合久中文字幕| 9久久9久久精品| 热综合一本伊人久久精品| 亚洲AV无码久久精品成人| 久久免费线看线看| 亚洲国产婷婷香蕉久久久久久|