主要差異
下列各節將討論 XInput 與 GameInput 之間的主要差異。C 與 C++
XInput API 是一組一般 C 函式。另一方面,GameInput 是 C++,並使用介面 (就像圖形和音訊 API 一樣)。實際上,這不會讓使用 GameInput API 的程式碼變得複雜,也不會影響效能,而且一旦您更熟悉 GameInput 的運作方式,就會發現它具有一些優點。 請務必了解,雖然這些介面看起來可能像 COM,但它們並不是。使用這些介面只需要對參考計數有基本的了解。如需詳細資訊,請參閱 GameInput 基本概念的介面一節主題。取得輸入
在 XInput 中,大多數遊戲會逐一查看使用者索引,直到找到具有已連線裝置的索引,然後從該裝置讀取狀態。遊戲通常會記住使用者索引,以便下次不需要再逐一查看。例如,下列程式碼是遊戲提示使用者在控制器上「按下 A」的典型程式碼:震動回饋
在 XInput 中,遊戲只需呼叫XInputSetState 即可將震動命令傳送至裝置。在 GameInput 中,遊戲需要取得裝置的 IGameInputDevice 執行個體,然後呼叫其 SetRumbleState 方法。這兩種方法的使用方式相似。這是您會呼叫裝置介面上的函式,而不只是將其作為裝置識別碼的一個範例。
應用程式焦點
在主機上,GameInput 只會在應用程式取得焦點時提供輸入給該應用程式。否則,傳回的狀態會包含中性或「靜止」值,就像使用者完全沒有碰觸裝置一樣。這樣就不需要額外的輸入程式碼來處理焦點變更 (例如呼叫XInputEnable)。
在 PC 上,輸入預設會傳送至所有處理序。未來,您將可以使用 SetFocusPolicy 方法變更此行為。
XInputOnGameInput 包裝函式
Microsoft Game Development Kit (GDK) 隨附一個名為XInputOnGameInput.h 的標頭檔,其中包含在 GameInput 之上實作的 XInput API。我們建議直接移植到 GameInput,尤其是當您需要鍵盤和滑鼠或其他輸入裝置時。不過,XInputOnGameInput 包裝函式可用來協助啟動初步的移植工作,而不需要對現有的 XInput 程式碼進行任何變更。
若要使用 XInputOnGameInput 包裝函式,只需將此程式碼:
XInput 與 XInputOnGameInput 之間的差異
一般而言,XInputOnGameInput 包裝函式可直接取代舊版 XInput API。不過,仍有一些細微差異:- 為了簡化,包裝函式中只撰寫了遊戲台裝置支援。如果您需要支援其他裝置,例如賽車方向盤或大型機台搖桿,請直接使用 GameInput,或在 XInputOnGameInput 程式碼中新增對這些裝置的支援。
-
包裝函式只會在遊戲取得焦點時傳回遊戲台輸入。當遊戲未取得焦點時,傳回的任何遊戲台狀態都會設為中性或「靜止」值,就像使用者沒有碰觸遊戲台一樣。無論是否呼叫
XInputEnable,都會如此處理。 -
XUSER_MAX_COUNT的值已從 4 增加為 8。對於大多數舊版 XInput 程式碼而言,這通常是透明的。不過,請務必仔細檢閱程式碼中對XInputGetKeystroke函式的任何使用,以協助確保沒有任何程式碼寫死假設XINPUT_KEYSTROKE結構的UserIndex成員中傳回的最大值為 4。否則,可能會發生緩衝區溢位。 - 已新增一些新函式 (請參閱下文),只有在您打算在生產程式碼中繼續使用 XInput 包裝函式時,這些函式才會有用。
在生產程式碼中使用 XInputOnGameInput
XInputOnGameInput 包裝函式以高效能且無鎖定的方式撰寫,繼承了 GameInput API 的所有效能最佳化,因此適合在生產程式碼中使用。它也繼承了 GameInput 更廣泛的裝置支援 (例如熱門的 HID 遊戲台),並在 API 中新增下列新函式:-
XInputSetStateEx與XInputSetState類似,但新增了對扳機馬達的支援。 -
XInputGetStateWithToken與XInputGetState類似,但允許呼叫端提供 D3DX 畫面管線權杖,將特定輸入讀數與圖形畫面產生關聯,以便稍後在 PIX 中進行分析。[!NOTE] 在 May Preview 版本中,
XInputGetStateWithToken目前的行為與XInputGetState相同,因為基礎的 GameInput 程式碼尚未完全實作。 -
XInputGetDeviceId會傳回指定使用者索引之裝置的APP_LOCAL_DEVICE_ID。將此識別碼傳遞至 IGameInput 上的 FindDeviceFromId 方法,會傳回該使用者索引對應的 IGameInputDevice。然後可以使用它來存取 GameInput API 中未透過 XInput 包裝函式公開的其他功能。
最佳化包裝函式程式碼
根據預設,XInputOnGameInput 包裝函式會設定為可直接相容於舊版 XInput API。不需要 100% 相容行為的遊戲,可以透過定義下列任一前置處理器巨集,微調包裝函式的行為和效能:XINPUT_ON_GAMEINPUT_EXPLICIT_INITIALIZATION
根據預設,XInput 包裝函式會在第一次呼叫任何包裝函式時,自動延遲初始化基礎的 GameInput API。這可確保與現有 XInput 程式碼的直接相容性,但有幾個小缺點:- 第一次呼叫 XInput 包裝函式的執行時間會比平常長。
- 每個 XInput 包裝函式在每次呼叫時,都必須檢查是否已執行延遲初始化。這只是對全域變數的簡單測試,因此分支預測器應該能降低成本,但仍是額外的負擔。
- 雖然它應該永遠不會失敗,但無法得知基礎 GameInput API 的延遲初始化是否成功。
- 在 XInput 包裝函式的全域變數清除之前 (由於模組卸載或處理序終止),基礎的 IGameInput 執行個體不會釋放。
XINPUT_ON_GAMEINPUT_EXPLICIT_INITIALIZATION 巨集,手動控制包裝函式的初始化和關閉。這會新增兩個新函式XInputOnGameInputInitialize 和XInputOnGameInputUninitialize,可以呼叫它們來精確控制初始化和關閉的時機。
XINPUT_ON_GAMEINPUT_NO_XINPUTENABLE
實作XInputEnable 函式所需的程式碼,會為每次呼叫XInputGetState、XInputGetStateWithToken、XInputSetState、XInputSetStateEx 和XInputGetKeystroke 函式增加額外負擔。如果您的程式碼不會呼叫XInputEnable,或可以輕鬆從程式碼中移除,定義XINPUT_ON_GAMEINPUT_NO_XINPUTENABLE 巨集將會移除對XInputEnable 的支援及其帶來的相關負擔。基礎的 GameInput 程式碼無論如何都會在焦點變更時自動執行XInputEnable 的功能,因此大多數遊戲在可能的情況下都會想要定義此巨集。
XINPUT_ON_GAMEINPUT_NO_XINPUTGETKEYSTROKE
實作XInputGetKeystroke 函式所需的程式碼,會在包裝函式的實作中新增一些額外的函式和變數。它不會為任何其他 XInput API 函式增加負擔,但如果您的程式碼不會呼叫XInputGetKeystroke,您可以定義XINPUT_ON_GAMEINPUT_NO_XINPUTGETKEYSTROKE 巨集,稍微減少 XInput 包裝函式的程式碼/資料大小。
