1. 程式人生 > >掌握DirectX和DirectInput—力反饋遊戲杆 (2)

掌握DirectX和DirectInput—力反饋遊戲杆 (2)

 

使用DirectInput物件

一旦擁有了DirectInput物件,就可以用它來建立DirectInputDevice物件,來管理系統中特定的裝置。建立DirectInputDevice物件要使用CreateDevice函式,它是作為IdirectInput介面一部分的五個函式之一。CreateDevice需要所請求裝置的GUID,返回新DirectInputDevice物件的IdirectInputDevice介面指標。

HRESULT CreateDevice(

  REFGUID rguid, 

  LPDIRECTINPUTDEVICE *lplpDirectInputDevice, 

  LPUNKNOWN pUnkOuter 

);

這些內容看起來很熟悉,因為它與CoCreateInstanceDirectInputCreate類似。但是,現在還沒有完全準備好開始DirectInputDevice物件,原因是在建立DirectInputDevice物件前需要該裝置的GUID

     DirectInput庫為建立DirectInputDevice物件預定義了兩個GUIDGUID_SysKeyboardGUID_SysMouse。將兩者之一直接傳遞給CreateDevice函式,就會得到相應裝置的DirectInputDevice物件。

注意,令人感到奇怪的是缺少對遊戲杆的預定義GUID。在Windows中,通常都有系統鍵盤和系統滑鼠,另一方面,系統本身並不使用遊戲杆。可以安裝一個或者多個遊戲杆,但系統管理的範圍只限於驅動程式級。系統併為這些裝置指定特殊的系統狀態,也不會在日常事務中使用這些裝置。因此,為遊戲杆定義GUID

DirectInput來說是不合理的。

那麼,如何才能找到與系統連線的遊戲杆的GUID呢?要得到它們,必須要列舉裝置。列舉系統裝置和效能在DirectX中相當普遍。要列舉系統中的輸入裝置,需要使用EnumDevices函式。EnumDevicesIdirectInput介面的一部分,如下定義:

HRESULT EnumDevices(

  DWORD dwDevType, 

  LPDIENUMCALLBACK lpCallback, 

  LPVOID pvRef, 

  DWORD dwFlags 

);

注意此函式與Windows中其它列舉API相同,例如EnumWindows

。第二個引數是一個回撥函式。第三個引數是程式中定義的32位值。第一個引數是想要列舉的裝置型別,對遊戲杆來說,是DIDEVTYPE_JOYSTICK(全部的裝置型別列在表4中)。最後一個引數是詳細描述想要列舉的裝置的標誌。現在支援的標誌是DIEDFL_ATTACHEDONLYDIEDFL_ALLDEVICES(這兩個標誌是互斥獨佔的),此外還有DIEDFL_FORCEFEEDBACK,此標誌表示力反饋裝置,能夠和另兩個標誌位或操作。

4:定義列舉的輸入裝置

以下定義的值可以傳遞給EnumDevices來選擇列舉哪種型別的輸入裝置。另外也支援子型別,見SDKDIDEVICEINSTANCE結構的文件。

說明

DIDEVTYPE_MOUSE

列舉滑鼠裝置 (標準、軌跡球等)

DIDEVTYPE_KEYBOARD

列舉鍵盤裝置 (標準、鍵區等)

DIDEVTYPE_JOYSTICK

列舉遊戲杆裝置 (操縱桿、操縱輪、方向舵等)

DIDEVTYPE_DEVICE

列舉其它裝置

EnumDevices列舉系統中的輸入裝置時,反覆地呼叫回撥函式。回撥函式定義如下:

BOOL CALLBACK EnumProc(LPCDIDEVICEINSTANCE lpddi,LPVOID pvRef) ;

因為回撥函式是由使用者程式定義並傳遞給EnumDevices的,所以是呼叫CreateDevice的最合適地方,直到建立了滿足需要的足夠DirectInputDevice物件為止。但是回撥函式並非一定要如此實現,可以簡單的將列舉裝置的所有GUID儲存在一個表中,在以後的程式碼中使用。

回撥函式接受兩個引數。第二個引數是程式定義的傳遞給EnumDevices32位值。更重要的是,第一個引數傳遞指向一個結構的指標,該結構包含關於能夠與列舉標準匹配的單個裝置的許多資訊。這是一個DIDEVICEINSTANCE結構。此結構中最重要的一條資訊是裝置的GUID,儲存在結構的guidInstance成員中。

當程式中完全完成DirectInput有關的工作後,就應該呼叫IdirectInput介面的Release成員。這就告訴DirectInput物件可以釋放自己了。在DirectX中,最好養成釋放物件的習慣,從低層物件開始,到高層物件結束。正常情況下程式會作為清除或者關閉的例行公事的一部分呼叫Release。這是使用每個DirectX元件的必要步驟,也是使用每個COM元件的必要步驟。

現在已經用CreateDevice成員函式獲得了DirectInputDevice物件的一個介面,為開始處理與系統連線的實際物理裝置做好了準備。

使用DirectInputDevice物件

     DirectInputDevice物件的每個例項都與系統中的特定裝置相關。此物件提供了對系統硬體更多的控制和能力,從而使DirectX的允諾實現。下面討論擁有了DirectInputDevice物件後下一步幹什麼。

擁有了IdirectInputDevice介面的一個介面指標,現在幹什麼?首先,設定裝置的資料格式。通過呼叫SetDataFormat來完成,該函式是一個介面成員函式。設定資料格式包括無數可能的決定,包括軸資訊、相對或絕對座標資訊、等等。所有這些細節通過一個叫作DIDATAFORMAT的結構傳遞給此函式。實際上,SetDataFormat唯一的引數就是指向此結構的指標。

填寫這個結構的細節會使人發憷。值得感謝的是這一工作並不是必須的,因為DirectInput已經定義了幾個DIDATAFORMAT結構變數,可以用於比較普通的輸入裝置:c_dfDIKeyboard, c_dfDIMouse, c_dfDIJoystick, c_dfDIJoystick2。為普通的力反饋遊戲杆設定資料格式,可以使用下面的呼叫形式:

lpdid->SetDataFormat( &c_dfDIJoystick ) ;

在此例中,lpdid是指向IdirectInputDevice介面的指標。

設定完裝置物件的資料格式後,就需要設定裝置的協作級別。因為協作級別在整個DirectX中很常見,所以這裡要做一下說明。大多數直接處理系統硬體的DirectX物件在介面的成員中都有一個叫作SetCooperativeLevel函式。這個函式很重要,因為它定義了程式操縱與系統中其它程序有關的硬體的控制級別。同其它DirectX物件一樣,只有設定了協作級別才能使DirectInputDevice物件工作。要理解協作級別,就需要熟悉Acquire函式。呼叫此函式是為了獲得對物理裝置的實際訪問(不要和邏輯上的DirectInputDevice物件混了)。相反的,Unacquire函式釋放對物理裝置的訪問。

下面是函式SetCooperativeLevel的定義:

HRESULT SetCooperativeLevel(

  HWND hwnd,     

  DWORD dwFlags  

);

     hwnd是程式的主視窗。標誌是下面一些值的或操作的結合: DISCL_BACKGROUND, DISCL_FOREGROUND, DISCL_EXCLUSIVE, DISCL_ NONEXCLUSIVE

如果標誌引數中或上了DISCL_EXCLUSIVE,則當獲得裝置後本程式就成為唯一允許訪問該物理裝置的程序。另一方面,如果選擇了DISCL_NONEXCLUSIVE,那麼系統中可以有多個程序同時協作獲得和使用該裝置。如果或上了DISCL_BACKGROUND,程式將不會失去物理裝置。然而,象Ctrl+Alt+Del組合鍵被按下這樣的系統事件仍然能夠隱含地“unacquire”程式中的裝置。如果使用了DISCL_ FOREGROUND,當不是活動視窗時,程式將會自動釋放物理裝置。這就是將程式主視窗控制代碼傳遞給SetCooperativeLevel的意義。DirectX根據視窗是否是系統當前活動視窗自動調整裝置共享。

那麼所有這些值的意義是什麼呢?下面舉個例子說明。如果力反饋遊戲杆的協作模式是DISCL_FOREGROUND | DISCL_EXCLUSIVE,那麼只要程式處於活動狀態,就能夠從遊戲杆讀資料並播放力反饋效果(力反饋需要exclusive-level協作)。只要使用者一選擇其它程式,程式就失去對物理裝置的控制,新啟用的程式就能夠訪問該裝置。這意味著在除錯程式時,如果切換到偵錯程式視窗,程式就會因為視窗變為非活動的而失去對遊戲杆的控制。

如果將同一遊戲杆的協作級別設為DISCL_BACKGROUND | DISCL_EXCLUSIVE將會是什麼情況呢?程式將會所有時間都能訪問遊戲杆,不管視窗的狀態。但是現在系統中其它程序就不能獲得遊戲杆,除非程式釋放了遊戲杆,不管使用者在做什麼!

非常明顯,在正式釋出的產品中應該使用DISCL_FOREGROUND | DISCL_EXCLUSIVE,而在除錯版本中應該使用DISCL_BACKGROUND|DISCL_EXCLUSIVE。但是也不總是這樣選擇。例如,如果裝置是系統鍵盤,那麼DirectInputDevice想獨佔使用而呼叫SetCooperativeLevel將會失敗。這是因為作業系統想要允許使用者自由地從一個程式切換到另一個程式。類似的,DirectInputDevice不會允許以協作級別DISCL_BACKGROUND|DISCL_EXCLUSIVE請求系統滑鼠。Windows不希望一個程式能夠完全將使用者與作業系統的聯絡切斷。

在能夠從物理裝置讀取資訊或向物理裝置傳送資訊之前,必須要用Acquire獲得裝置。在臨時或永久結束裝置使用時要明確地使用Unacquire函式釋放裝置。但Unacquire並不是失去裝置控制的唯一方法。

如果設定協作級別時使用DISCL_FOREGROUND標誌,那麼程式的主視窗不再是系統中的活動視窗時裝置將被明確釋放。這就是說,在程式呼叫Acquire和實際試圖從裝置讀取資訊之間,能夠失去對裝置的佔有。所以需要檢查返回值來捕捉這樣的錯誤,並準備好在任何時間重新獲得該裝置。

關於AcquireUnacquire的決定性要點:當程式獲得獨佔協作級別的裝置時,DirectX擁有該裝置。例如,如果滑鼠被DirectX(獨佔)獲得,那麼程式視窗中的按鈕就不會對滑鼠做出響應。這就是說,如果想讓Windows對裝置響應,就應該釋放該裝置。換句話說,如果不想讓DirectInput從裝置中讀取資料,就呼叫Unacquire

設定完裝置的協作級別後,接著應該為裝置配置其它設定。獲得了裝置後,接著就應該開始使用GetDeviceState函式輪流檢測輸入的資料。當完成與裝置物件的操作後,呼叫Unacquire釋放DirectInputDevice物件。裝置與裝置之間存在細節上的差別;下面講解遊戲杆和鍵盤,應該能為從其它裝置讀取輸入提供足夠的基礎知識。

鍵盤

鍵盤是到目前為止最容易讀取的裝置。實際上,設定完資料格式、協作級別、獲得裝置以後,就可以讀取鍵盤狀態了。讀取鍵盤狀態要使用IdirectInputDevice介面的GetDeviceState成員。GetDeviceState用關於物理裝置的狀態資訊組裝一個結構,所組裝結構的型別由前面對SetDataFormat的呼叫決定。對鍵盤來說,此資料結構是一個簡單的256個位元組組成的陣列。每個位元組對應於鍵盤上的一個鍵,如果某個鍵按下,相應位元組的高位就被設定。

     DirectInput定義了一套以DIK_XXX為字首的常量,這些常量可以用來索引位元組陣列以找到關於特定鍵的資料。例如,如果要檢查右Shif鍵當前是否按下,可以使用DIK_RSHIFT定義:

GetDeviceState(256,(LPVOID) cKeyboardData) ;

if(cKeyboardData[DIK_ RSHIFT]&0x80)

    DoWhatever() ;

     CKeyboardData256個位元組的緩衝區。幾乎就是這麼簡單,但是要記住,不管GetDeviceState在何時返回DIERR_INPUTLOST,就必須使用Acquire獲得裝置。這種情況發生在每次使用者從程式切換離開的時候。

還有一點很重要,就是能夠請求DirectInput緩衝鍵盤資訊。這要求提供一個緩衝區並使用SetProperty為裝置設定緩衝區大小。在本文中沒有篇幅討論這一技術,但這一技術在程式不能相當頻繁的檢查鍵盤狀態時非常有用。使用者有可能在程式中兩次GetDeviceState呼叫之間按下又鬆開了一個鍵,如果DirectInput不緩衝鍵盤資料的化,這種擊鍵動作就丟失了。

遊戲杆

遊戲杆非常好玩。與其好聽的名稱(Joystick——原意為歡樂杆)相符,這種裝置為遊戲體驗添加了許多樂趣,同時也為程式設計師的體驗添加了一些東西。正常情況下,通過呼叫IdirectInput介面的CreateDevice成員得到IdirectInputDevice介面(和物件),這對遊戲杆也適用。

但是開發人員都希望立即將介面升級到IDirectInputDevice2,那麼可以象下面這樣使用QueryInterface呼叫請求CreateDevice返回新的介面:

hr = lpDIDeviceJoystickTemp->QueryInterface(     IID_IDirectInputDevice2, 

    (void **) &g_lpDIDeviceJoystick);

如果成功,就可以釋放原來的介面,開始使用漂亮的新IDirectInputDevice2介面。但是為什麼要這麼做呢?IDirectInputDevice2介面提供IdirectInputDevice的所有功能,而且還有另外兩個重要特性:支援查詢裝置和支援力反饋裝置。

其次,需要設定上的一些考慮。還記得SetDataFormat定義了GetDeviceState返回的資料的型別。對於遊戲杆裝置,使用c_dfDIJoystickc_dfDIJoystick2兩個預定義變數之一,將返回資料的型別設定為DIJOYSTATEDIJOYSTATE2結構。選擇哪種主要取決於要使用遊戲杆哪種型別的特性。瀏覽這些結構中的成員應該對弄清這個問題有幫助。

同所有輸入裝置一樣,要為遊戲杆設定資料格式和協作級別。遊戲杆往往比鍵盤需要更多一點注意。這是因為現在還幾乎沒有功能完美的遊戲杆,所以程式應該檢查以確保控制的裝置能滿足要求。如果不能,就調整要求或者提醒使用者遊戲杆太落後!裝置的能力可以並且應該呼叫IdirectInputDevice介面的成員函式GetCapabilities探測。

這就引出了適用於所有DirectX元件的另一個討論點。DirectX為多種裝置提供廣泛的支援。軟體開發環境和使用環境可能有很大差別,不同的計算機支援不同水平的DirectX功能。編寫好使用DirectX的軟體,需要檢查硬體的能力。最差的情況下,如果某個功能不支援,可以退出程式。最好的情況當然是程式能夠聰明地根據缺少的特性調整本身的需求。

在開始從裝置得到輸入之前,需要設定裝置的特性。這些特性包括象返回值的範圍、遊戲杆的中心點等此類的細節。這一工作由函式SetProperty完成,相當複雜。

     SetProperty設定裝置的一個特性。首先,必須使用關於要改變的設定的一些資訊填寫一個數據結構。請參考Platform SDK中的文件,得到所有資料結構。每個結構都以一個DIPROPHEADER結構開始,此結構中填寫描述要改變的設定的資訊。然後,用特定於所改變的設定的資料填寫結構中剩餘的部分。最後,呼叫SetProperty,引數是GUID和指向結構中DIPROPHEADER部分的指標。下面的程式碼片段將遊戲杆的垂直範圍設定為–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) ;


     此結構中最難懂的部分是diph.dwObjdiph.dwHowdiph.dwHow描述diph.dwObj中儲存何種資訊。diph.dwObj實際描述哪個屬性被設定。大多數情況下,diph.dwHow的值是DIPH_BYOFFSETdiph.dwObj的值是傳遞給SetDataFormat的結構中一個預定義的偏移。

應該指出能夠列舉裝置的物件,包括按鈕和其它特點。這一工作由EnumObjects函式完成。這樣做時,應該提供一個物件標誌符。將此標誌符傳遞給diph.dwObj成員,將diph.dwHow成員填寫為DIPH_BYID

在從裝置讀取資料之前,至少要為裝置的XY座標軸設定最小和最大值。設定好裝置屬性後,就可以獲得裝置並開始從裝置獲得資料。從遊戲杆獲取資料與從鍵盤或滑鼠獲取資料不同,因為遊戲杆是查詢裝置。

鍵盤和滑鼠會引發硬體中斷,由系統中的驅動程式處理,並用來更新通過呼叫GetDeviceStateDirectInput返回的資料。查詢裝置(如大多數遊戲杆)不產生硬體中斷,因此,DirectInput必須被告知從裝置獲取狀態資訊。這一工作通過呼叫IDirectInputDevice2介面的Poll成員函式完成。此時也是檢查裝置是否需要重新獲得的適當時機。裝置被成功查詢後,就可以呼叫GetDeviceState獲取狀態資訊。

如果呼叫SetDataFormat時使用c_dfDIJoystick變數,那麼GetDeviceState將用遊戲杆當前的狀態資訊填充一個DIJOYSTATE結構。此結構的內容主要取決於物理裝置的特性和SetProperty的設定。例如,如果結構中的lY成員等於-50,並且Y軸的範圍設定為-100100,那麼就是說遊戲杆在垂直方向上處於中心和最頂端的中間。程式中應該確保裝置的範圍設定為能合理滿足需求的值。為了從遊戲杆裝置中獲取資料,程式應該定期查詢裝置。

使用DirectInputEffect

首先,應該解釋一些力反饋技術。力反饋裝置是能夠產生使用者可以感覺到的力的裝置,這些力叫作效果,例如顛簸效果或者持續的將操縱桿推向右上方的力。這些效果是“播放”出來的,效果由程式控制播放,或者對函式呼叫響應,或者對使用者按鍵自動反應。

     DirectInput目前支援大約一打不同的效果型別(見表5)。這些效果的範圍從完全由程式控制的低階持續力效果,到由DirectInput或裝置自己控制的高階傾斜或波動效果。效果有四種基本型別:持續力、傾斜效果、週期效果和條件。持續力是單一方向上不改變強度的力。傾斜效果是強度隨時間線性變化的持續的力。週期效果是沿著給定的軸重複變化,其量級或者力的強度由週期效果定義。條件是對使用者與遊戲杆的互動作用做出響應的效果。這種效果可能是象一根彈簧,操縱桿向某個方向推得越遠,反彈力就越強。

5DirectInput效果的型別

GUID

說明

使用方法註解

GUID_ConstantForce

固定強度、特定方向的持續拉力。

使用DICONSTANT力結構作為DIEFFECT結構的一部分實現持續力。

GUID_CustomForce

一序列持續力下傳到裝置,按順序播放。

DICUSTOMFORCE結構被用來定義力。

GUID_Damper

隨沿座標軸的移動增加的條件效果。

實現這種效果的特定型別結構是DICONDITION結構。條件效果通常不支援包。

GUID_Friction

阻礙沿座標軸移動的條件效果。

實現這種效果的特定型別結構是DICONDITION結構。條件效果通常不支援包。

GUID_Inertia

隨沿座標軸移動的加速度增加的條件效果。

實現這種效果的特定型別結構是DICONDITION結構。條件效果通常不支援包。

GUID_RampForce

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

DIRAMPFORCE結構被用來作為DIEFFECT結構中的型別相關部分。

GUID_SawtoothDown

力瞬間達到最大然後線性減小到最小的週期效果。

需要的特定型別結構是DIPERIODIC結構。

GUID_SawtoothUp

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

需要的特定型別結構是DIPERIODIC結構。

GUID_Sine

力正弦變化的週期效果。

需要的特定型別結構是DIPERIODIC結構。

GUID_Spring

力隨到某個中點的相對距離而增大的條件效果。

實現這種效果的特定型別結構是DICONDITION結構。條件效果通常不支援包。

GUID_Square

力瞬時在最大與最小之間轉變的週期效果。

需要的特定型別結構是DIPERIODIC結構。

GUID_Triangle

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

需要的特定型別結構是DIPERIODIC結構。

下面所有與力反饋遊戲杆有關的工作都是針對Microsoft SideWinder Force Feedback Pro遊戲杆,這就是說,本文中的某些細節對其它裝置可能多少會產生一些問題。

在建立力反饋效果以前先獲得裝置是一個不錯的想法。雖然這不是必須的,但是在效果能夠被下傳到裝置前必須要獲得裝置。這一點對於播放對使用者按下按鈕做出反應的力效果尤其重要。

要建立效果,首先要為每個打算使用的效果建立DirectInputEffect物件的例項。這一工作通過呼叫IDirectInputDevice2介面的CreateEffect成員函式完成。此函式需要效果的GUID,以及指向DIEFFECT結構的指標,該結構中填寫的是效果的細節。最後,CreateEffect返回一個指向IdirectInputEffect介面的指標,該指標的地址是CreateEffect的一個引數。這個呼叫的核心部分集中在DIEFFECT結構的填充。

     DIEFFECT結構如下定義:

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成員是此結構的位元組數。DwFlags指出效果使用的座標型別,以及是使用偏移方法還是ID方法描述按鈕(就向前面說明的SetProperty)。通常情況下,可以設定為DIEFF_CARTESIAN|DIEFF_OBJECTOFFSETS,即按鈕採用偏移描述,座標使用XYZ座標形式。

DwDuration說明效果播放多少毫秒。注意dwDuration可以設為INFINITEDwSamplePeriod說明效果播放一個週期花費多少毫秒。不同裝置支援不同的週期。實際中,SideWinder遊戲杆支援的週期不大於1秒,不小於1/80秒。DwGain可以看作效果的主要量,因為它說明效果多麼有力。此值的範圍是010000

DwTriggerButtondwTriggerRepeatInterval用來設定觸發效果播放的按鈕,以及重複頻率。當然,可以通過將dwTriggerButton的值設定為DIEB_NOTRIGGER來將效果設定為與按鈕無關。否則,dwFlags定義通過ID還是偏移方式描述按鈕。因為偏移方式不需要呼叫EnumObjects,所以一般可以將值指定為DIJOFS_ BUTTON0DIJOFS_BUTTON1

CAxes成員說明效果將影響幾個軸。RgdwAxes指向一個描述所包含的軸的DWORD陣列,陣列中每個軸是一個成員。同按鈕一樣,軸也是用偏移或者ID來指明。一般的偏移值包括DIJOFS_XDIJOFS_Y

同樣,rglDirection成員指向一個long型陣列,每個軸是一個成員。在笛卡兒座標中,(Y=-1X=1)與(Y=-10X=10)描述的是同一個方向。這就是說,如果想得到一個不是45度整數倍方向上的斜的力,就應該調整兩個值的相對大小。例如,(Y=-10X=1)描述與上面例子在同一象限的方向,但卻明顯靠近Y軸。

效果也可以有描述它們的包。填充一個DIENVELOPE結構,並將其地址填寫到lpEnvelope成員就可以完成。包可以在一段時間內影響效果的數量或力量。其中,起動水平是效果的開始變化點,啟動時間說明效果達到力量保持階段花費多少毫秒。衰減水平是效果在包最後達到的水平,衰減時間是衰減用掉了多少豪秒。包可以用來製造初始狀態較強,然後慢慢衰減的力效果。圖1中描繪了包如何改變效果。

 

1:包效果

     DIEFFECT結構的最後兩個成員是cbTypeSpecificParamslpvTypeSpecificParams。它們儲存特定於所建立效果型別的結構的位元組數和地址。特定型別的效果使用何種結構的資訊見表5

填寫完這個結構並呼叫CreateEffect後,就會獲得指向IdirectInputEffect介面的指標,現在可以使用此介面播放效果,改變效果等。如果沒有將效果聯絡到按鈕,就必須用IdirectInputEffect介面的StartStop成員播放和停止效果。如果效果與按鈕關聯,那麼在建立時下傳到裝置;否則,效果在播放時自動下傳到裝置。如果程式必須重新獲得裝置,那麼所有與按鈕相關的效果必須通過明確的呼叫Download成員才能下傳到裝置。

效果能夠用Unload成員解除安裝,也能夠通過向SetParameters成員函式傳遞新的DIEFFECT結構重新設定引數。當程式用完效果後,必須呼叫介面的Release成員。

演示例子

2:演示程式

首先,應該建立演示程式碼並執行,應該能看到一個遊戲杆配置視窗(見圖2)。使用遊戲杆可以移動中間的人,在視窗的左上角是座標和輸入狀態資訊。如果有力反饋遊戲杆,那麼通過按下按鈕12應該能感覺到一對不同的力。如果將小人撞到視窗的邊緣,應該能感到碰撞效果。

這個例子說明了DirectInput的使用。這裡仍然有相當數量的程式碼與DirectInput沒有直接關係。這些程式碼根據功能劃分成模組。Main.cpp是基本的WinMain樣板檔案和視窗建立程式碼。除了呼叫初始化函式外,這部分程式碼基本上與本文的其它部分沒有關係。它建立視窗,進入訊息迴圈。WndProc.cpp包含程式視窗的視窗過程。

     Demo.cpp開始了有意義的程式碼。不論何時提到“demo”,都是指程式遊戲。例如,InitDemo函式為圖形設定狀態資料並建立一些所需的時間和執行緒。除了初始化,此演示程式執行在第二個執行緒中。該執行緒嘗試讀取輸入並重新整理狀態資料,每秒進行32次。然後使視窗無效,從而讓主執行緒重新繪製視窗。這就是說,輸入和狀態變化的一個反覆,或者說一個演示週期,大約有1/32秒。所以,不管顯示重新整理得多麼頻繁,輸入響應速度都會保持一致。

     DX.cpp包含DirectX需要的非常小的初始化和結束處理,然後呼叫完成特殊DirectInput工作的函式。除了CoInitializeCoUninitialize外,DXInput模組包含本文中提到的所有內容。函式按照演示程式中用到的順序列出,每個只列一次。注意,DirectInput的大部分工作在初始化中完成。冗長的任務劃分成幾個函式列在表6中。

6DXInput.cpp的函式

成員函式

說明

InitDirectInput

為系統鍵盤初始化DirectInput物件和DirectInputDevice物件。

EnumJoy

列舉裝置的回撥函式。此函式為系統中安裝的第一個遊戲杆建立DirectInputDevice

InitForceFeedback

如果找到遊戲杆是適應力反饋的,此函式就為力反饋效果進行一些設定。

InitRampEffect, InitBumpEffects, InitWavyEffect

這些函式每個都設定一個效果。這些效果演示了DirectInput中幾種不同的效果,並且應該對建立新效果有用。

這個模組中的另一個要點是演示程式重複呼叫的函式。ForceEffect播放一個存在的效果,GetKeyboardInput獲得鍵盤輸入,GetJoystickInput獲得遊戲杆輸入。最後UnInitDirectInput結束所有的一切。

相關推薦

掌握DirectXDirectInput反饋遊戲 (2)

  使用DirectInput物件 一旦擁有了DirectInput物件,就可以用它來建立DirectInputDevice物件,來管理系統中特定的裝置。建立DirectInputDevice物件要使用CreateDevice函式,它是作為IdirectInput介面一部分

Luogu P2298 Mzc男家丁的遊戲

次數 turn center false empty 直接 using while 輸入格式 Mzc和男家丁的遊戲 題目背景 mzc與djn的第二彈。 題目描述 mzc家很有錢(開玩笑),他家有n個男家丁(做過上一彈的都知道)。他把她們召集在

Geomagic Touch X 專業級反饋設備

平臺 實的 快速 範圍 占用 24小時 可視化 占用空間 空間 產品概述:: Geomagic Touch X力反饋設備 屢獲殊榮的Geomagic Touch X(原Sensable Phantom Desktop)將力反饋性能提升到一個新的水平,可提供更精確的定位輸入和

Geomagic Touch反饋設備

life art 診斷 個人 碰撞檢測 通過 nova nom 技能 ::產品概述:: Geomagic Touch力反饋設備 Geomagic Touch(原Sensable PhantomOmni)是業界最廣泛配置的專業力反饋裝置。Touch用於研究、3D建模、OEM應

如何視覺化分析使用者反饋

從來沒有公司像現在這樣收到如此多的使用者反饋。拿手機應用程式來說:我們通過蘋果應用商店獲取資料,通過分析系統得到應用程式內部的運轉狀態,而且特別是通過蘋果應用商店的真實使用者中獲取評論和評級,在這個資料海洋裡隱藏著許多價值連城的資訊。 每天都有成千上萬的使用者在蘋果應用商店評論裡分享他們的想法。他們通

深入剖析 Web 伺服器與 PHP 應用之間的通訊機制 - 掌握 CGI FastCGI 協議的執行原理

本文首發於 深入剖析 Web 伺服器與 PHP 應用之間的通訊機制 - 掌握 CGI 和 FastCGI 協議的執行原理,轉載請註明出處! 身為一名使用 PHP 語言開發後端服務的程式猿,我們每天都和 PHP 以及 Web 伺服器產生無數次的親密接觸。得益於它們,我們才能

Geomagic Touch反饋裝置

::產品概述:: Geomagic Touch力反饋裝置 Geomagic Touch(原Sensable PhantomOmni)是業界最廣泛配置的專業力反饋裝置。Touch用於研究、3D建模、OEM應用等,使使用者能夠自由地進行3D粘土造型,加強科學或醫學模擬,通過互動式培訓提高生產力,並輕鬆地操縱機

Geomagic Touch X 專業級反饋裝置

產品概述:: Geomagic Touch X力反饋裝置 屢獲殊榮的Geomagic Touch X(原Sensable Phantom Desktop)將力反饋效能提升到一個新的水平,可提供更精確的定位輸入和高保真力反饋輸出。對於3D建模和設計、手術培訓、虛擬裝配等要求精確度較高的多種操作,TouchX

Cyberglove CyberTouch II 反饋手套

::產品概述:: Cyberglove CyberTouch II 力反饋手套 CyberTouch II系統為一款觸覺反饋選件,是指尖內側的小震動觸覺感測器,相比前一代產品可提供更真實的感官體驗。 概述 CyberTouch產品線的這一新型號將振動觸覺感測器應用到指尖的內側。這些小型感測器重量很輕,

使用分治法法求解最近點對

問題描述 對於平面上給定的N個點,給出所有點對的最短距離,即輸入是平面上的N個點,輸出是N點中具有最短距離的兩點。 求解 建立點類,使之具有兩個屬性,x座標和y座標 class myPoint { public: int x; //x座標 i

比較DirectXOpenGL的區別

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

Cozmo+Python+ROS+AI會產生什麼樣的奇妙反應呢? (玩Cozmo機器人,學Python程式設計,掌握ROSAI技術)

Cozmo+Python+ROS+AI會產生什麼樣的奇妙反應呢? (玩Cozmo機器人,學Python程式設計,掌握ROS和AI技術) 跟隨綠色鐳射點運動?如何實現? 在黃色邊緣線的賽道上行駛?如何實現? 這是一篇輕鬆愉快的博文,簡單聊聊如何從玩機器人,升級為開發和設

window.onload3的小遊戲

window.onload出現的原因?  我們都知道頁面的程式碼順序是從上往下進行載入,很多時候我們要對頁面中的某一個模組進行操作,這時候我們常常使用javascript程式碼來進行操作。為了能夠保證操作的模組或物件在js程式碼之前就載入了,我們不得不把js程式碼放在頁面的底端。但是我們在設計頁面的時候,為了

DirectXD3DX的區別

“Direct3D”和“D3DX”之間的區別一直有,但它一直比較模糊。 D3DX從Windows8 SDK開始就已經被棄用,可以視為DirectX 的一個擴充套件包。 D3DX的主要替代庫DirectXTK,DirectXTex,DirectXMesh。 這些都支援Direct3D 11

快手如何通過演算法支撐使用者的增長

自從玩了快手,相信你一定是這樣的......     如今,短視訊成了人們的新寵,閒暇時大家總是習慣性地拿出手機“刷刷刷”。而在眾多短視訊應用中,堅持“記錄生活,記錄你”的快手一直頗受大家青睞。   備受喜愛的背後,是北京快

SpriteKit快速入門新時代iOS遊戲開發指南

SpriteKit,iOS/Mac遊戲製作的新紀元 這是我的WWDC2013系列筆記中的一篇,完整的筆記列表請參看這篇總覽。本文僅作為個人記錄使用,也歡迎在許可協議範圍內轉載或使用,但是還煩請保留原文連結,謝謝您的理解合作。如果您覺得本站對您能有幫助,您可以使用RSS或郵件方式訂閱本站,這樣您將

基於CanvasReact極簡遊戲(二)

暫停處理 遊戲業務邏輯是與React元件聯絡比較緊的。 暫停處理的React元件如下所示: import React from 'react'; import './Pause.scss'; import * as MiniGame from '.

北京U3D外包團隊 UE4紅軍抗戰案例 Unity3D紅軍抗戰案例 UE4下載安裝虛幻4遊戲引擎

dex 除了 u3d 更新 團隊 文檔 在線演示 2015年 bsp 剛完整UE4紅軍抗戰案例 Unity3D紅軍抗戰案例,有在線演示(版權關系不方便發圖),有UE4或Unity項目定制外包開發的歡迎聯系我們 進入虛幻4的官方主頁(https://www.unrealen

反饋hapticFeedbackEnabled屬性的用法!!!

摘要:為了實現單擊某個檢視,系統提供一個觸力反饋(震動一下),我們需要寫兩個地方:1)在xml配置檔案中,對要提供觸力反饋的檢視控制元件,設定其屬性android:hapticFeedbackEnabled="true",這是必需的,只有在isHapticFeedback

深入剖析 Web 伺服器與 PHP 應用之間的通訊機制 – 掌握 CGI FastCGI 協議的執行原理

身為一名使用 PHP 語言開發後端服務的程式猿,我們每天都和 PHP 以及 Web 伺服器產生無數次的親密接觸。得益於它們,我們才能夠如此快速的構建出令人陶醉的 Web 產品。 儘管我們已經和 Web 伺服器和 PHP 建立起深厚的友誼,但你知道它們之間為何能夠配合的如