此頁面說明使用 Windows.Gaming.Input.RacingWheel 和通用 Windows 平臺 (UWP) 相關 API,在 Xbox One 上為賽車方向盤進行程序設計的基本概念。
閱讀此頁面後,您將瞭解:
- 如何收集已連接的賽車方向盤及其使用者的清單
- 如何偵測賽車方向盤已新增或移除
- 如何從一個或多個賽車方向盤讀取輸入
- 如何傳送力回饋指令
- 賽車方向盤如何作為UI導航裝置運作
賽車方向盤概觀
賽車方向盤是類似真實賽車駕駛艙感覺的輸入設備。 賽車方向盤是無論在電玩式或模擬式賽車遊戲中,針對汽車或卡車的完美輸入裝置。 Windows 10 或 Windows 11 及 Xbox One UWP 應用程式均支援賽車方向盤,這是由 Windows.Gaming.Input 命名空間所支援。
賽車方向盤提供多種價格選擇,通常價格越高,輸入性能和力回饋功能也越強大。 所有賽車方向盤都配備了類比方向盤、模擬節流和剎車控制,以及一些輪上按鈕。 有些賽車方向盤還配備了類比離合器和手煞車控件、排檔模式和力回饋功能。 並非所有賽車方向盤都配備相同的一組功能,而且可能也因某些功能的支援而有所不同,例如,方向盤可能支援不同的旋轉範圍,而模式換檔器可能支援不同的齒輪數目。
裝置功能
不同的賽車方向盤提供不同的選用裝置功能集合,以及這些功能的不同支援層級;單一輸入裝置之間的這種變化層級,在 Windows.Gaming.Input API 支援的裝置之間是唯一的。 此外,您遇到的大部分裝置至少會支援一些選擇性功能或其他變化。 因此,請務必個別判斷每個連接賽車方向盤的功能,並支援符合您的遊戲需求的完整功能變化。
如需詳細資訊,請參閱 判斷賽車方向盤功能。
力回饋
有些賽車方向盤提供真正的力反饋,也就是說,他們可以在控制軸上套用實際力,例如方向盤,而不只是簡單的振動。 遊戲利用這項能力來創造更強的沉浸感(模擬車禍損壞和“道路感”),並增加駕駛的挑戰。
如需詳細資訊,請參閱 力回饋概觀。
使用者介面導覽
為了減輕支援不同輸入設備以進行使用者介面瀏覽的負擔,以及鼓勵遊戲與裝置之間的一致性,大部分的實體輸入設備會同時作為稱為UI流覽控制器的個別邏輯輸入設備。 UI 瀏覽控制器提供跨輸入裝置的UI瀏覽命令通用詞彙。
由於他們對類比控件的獨特關注以及不同賽車方向盤之間的變化程度,它們通常配備數位 D-pad、View、Menu、A、B、X、Y 按鈕,這些按鈕類似於 遊戲控制器的按鈕;這些按鈕並非用於支援遊戲命令,也不易作為賽車方向盤按鈕進行存取。
作為 UI 導覽控制器,賽車方向盤會將導覽命令所需的 集 對應至左側搖桿、D-pad、檢視、功能表、A和 B 按鈕。
導航命令 | 賽車方向盤輸入 |
---|---|
向上 | 向上方向鍵 |
向下 | 方向鍵向下 |
左側 | 方向鍵向左 |
正確 | 右 D 鍵 |
查看 | 檢視按鈕 |
菜單 | 選單按鈕 |
接受 | 按鈕 |
取消 | B 按鈕 |
此外,某些賽車方向盤可能會將部分 選擇性集合 導覽指令對應到它們支援的其他輸入,但每個裝置的命令對應可能有所不同。 也請考慮支持這些命令,但請確定這些命令對於瀏覽遊戲的介面並不重要。
導航命令 | 賽車方向盤輸入 |
---|---|
向上頁 | 會因 而異 |
頁面下移 | 會因 而異 |
左頁 | 會因 而異 |
右邊頁面 | 會因 而異 |
向上滑動 | 會因 而異 |
向下捲動 | 會因 而異 |
向左滾動 | 會因 而異 |
向右捲動 | 會因 而異 |
內容 1 | X 按鈕(通常為) |
內容 2 | Y 按鈕(通常為) |
內容 3 | 會因 而異 |
內容 4 | 會因 而異 |
偵測和追蹤賽車方向盤
偵測和追蹤賽車方向盤的運作方式與遊戲控制器完全相同,只是使用 RacingWheel 類別,而不是使用 Gamepad 類別。 如需詳細資訊,請參閱 遊戲手柄和震動。
解析賽車方向盤
確認您感興趣的賽車方向盤之後,即可開始從它們獲取反饋資訊。 不過,與您可能熟悉的一些其他類型的輸入不同,賽車方向盤不會透過觸發事件來傳達狀態變更。 相反地,您會 輪詢 來定期閱讀其目前的狀態。
輪詢賽車方向盤
輪詢會在精確的時間點擷取賽車方向盤的快照。 輸入收集的這種方法適合大部分的遊戲,因為它們的邏輯通常會在確定性循環中執行,而不是事件驅動,從一次收集的所有輸入中解讀遊戲命令通常也比較簡單,與其從一段時間內收集的許多單一輸入中解讀相比要容易得多。
您可以呼叫 GetCurrentReading來輪詢賽車方向盤;此函式會傳回一個 RacingWheelReading,其中包含賽車方向盤的狀態。
下列範例會檢測方向盤的目前狀態。
auto racingwheel = myRacingWheels[0];
RacingWheelReading reading = racingwheel->GetCurrentReading();
除了賽車方向盤的狀態,每個讀取都包含一個時間戳記,精確顯示狀態被擷取的時間。 時間戳適用於與先前讀取的時間或遊戲仿真的時間相關。
判斷賽車方向盤性能
許多賽車方向盤的控制元件都是可選的,即使在必備的控制元件方面,也支援不同的變化,因此您必須個別確定每個賽車方向盤的功能,才能處理在每次讀取過程中收集的輸入。
選用的控件是手布拉克、離合器和模式移位器;您可以分別讀取賽車方向盤的 HasHandbrake、 HasClutch 和 HasPatternShifter 屬性,來判斷連接的賽車方向盤是否支持這些控件。 如果屬性的值為 true,則支援該控件;否則不支援。
if (racingwheel->HasHandbrake)
{
// the handbrake is supported
}
if (racingwheel->HasClutch)
{
// the clutch is supported
}
if (racingwheel->HasPatternShifter)
{
// the pattern shifter is supported
}
此外,可能有所不同的控件是方向盤和模式換檔。 方向盤可能會因實際方向盤可支援的實體旋轉程度而有所不同,而模式換檔器可能會因支援的不同向前齒輪數目而有所不同。 您可以通過讀取賽車方向盤的 MaxWheelAngle
屬性來確定實際方向盤所支持的最大旋轉角度,其值是順時針(正數)方向的最大支持物理角度,同時也在逆時針(負數)方向中支持。 您可以藉由讀取賽車方向盤的 MaxPatternShifterGear
屬性,來判斷樣式排檔桿所支援的最大前進檔位;其值為所支援的最高前進檔位,包含,也就是說,如果其值為 4,則樣式排檔桿支援倒擋、空檔、第一檔、第二檔、第三檔和第四檔。
auto maxWheelDegrees = racingwheel->MaxWheelAngle;
auto maxShifterGears = racingwheel->MaxPatternShifterGear;
最後,一些賽車方向盤支持通過方向盤強制反饋。 您可以藉由讀取賽車方向盤的 WheelMotor 屬性,判斷連接的賽車方向盤是否支持強制回饋。 如果 WheelMotor
不是 null,則支援力回饋;否則不支援。
if (racingwheel->WheelMotor != nullptr)
{
// force feedback is supported
}
如需了解如何使用支援該功能的賽車方向盤的力回饋功能,請參閱 力回饋概觀。
閱讀按鈕
每個賽車方向盤的按鈕—方向鍵的四個方向、上一個排檔、下一個排檔 按鈕,以及 16 個額外的按鈕—都提供數位讀數,顯示它是按下(向下)還是釋放(向上)。 為了提高效率,按鈕讀數不會表示為個別布爾值,反之,它們全部打包成由 RacingWheelButtons 列舉所代表的單一位元欄位。
備註
賽車方向盤配備了用於UI導航的其他按鈕,例如 檢視 和 選單 按鈕。 這些按鈕不屬於 RacingWheelButtons
列舉的一部分,僅能通過將賽車方向盤用作用戶介面導航設備來讀取。 如需詳細資訊,請參閱 UI 導覽裝置。
按鈕值從 Buttons
結構中的 屬性獲取。 由於此屬性是位元欄位,因此會使用位元遮罩來隔離您感興趣的按鈕值。 當對應的位元被設定時,按鈕被按下(向下);否則,按鈕被釋放(向上)。
下列範例會判斷是否按下 [下一個齒輪] 按鈕。
if (RacingWheelButtons::NextGear == (reading.Buttons & RacingWheelButtons::NextGear))
{
// Next Gear is pressed
}
下列範例會判斷 [下一個檔位] 按鈕是否已被鬆開。
if (RacingWheelButtons::None == (reading.Buttons & RacingWheelButtons::NextGear))
{
// Next Gear is released (not pressed)
}
有時候,您可能希望判斷按鈕從按下轉變到放開或從放開轉變到按下的狀態,是否有多個按鈕被按下或放開,或是判斷一組按鈕是否以某特定方式排列,即部分按下,部分未按下。 如需如何偵測這些條件的資訊,請參閱 偵測按鈕轉換 和 偵測複雜按鈕排列。
解讀命運之輪
方向盤是一個必要的控制機制,它提供 -1.0 到 +1.0 之間的模擬讀數。 -1.0 的值對應至最左邊的方向盤位置;值 +1.0 會對應到最右邊的位置。 方向盤的值是從 Wheel
屬性讀取,該屬性屬於 RacingWheelReading 結構。
float wheel = reading.Wheel; // returns a value between -1.0 and +1.0.
雖然方向盤讀數會根據實體賽車方向盤支援的旋轉範圍,對應到實際方向盤中不同程度的旋轉,但您通常不需要調整這些讀數;支援更大旋轉度數的賽車方向盤只是提供更高的精確度。
讀取節流和剎車
油門和煞車是必備控件,每個控件都分別提供以浮點數值表示的模擬讀數,範圍介於0.0(完全釋放)和1.0(完全按下)之間。 節流控件的值是從 Throttle
結構的 屬性讀取,剎車控件的值則是從 Brake
屬性讀取。
float throttle = reading.Throttle; // returns a value between 0.0 and 1.0
float brake = reading.Brake; // returns a value between 0.0 and 1.0
了解手煞車與離合器
手煞車和離合器是可選的控制項,每個控制項都提供以浮點值表示的模擬讀數介於 0.0(完全釋放)與 1.0(完全啟動)之間。 handbrake 控件的值是從 Handbrake
結構 屬性讀取;離合器控件的值是從 Clutch
屬性讀取。
float handbrake = 0.0;
float clutch = 0.0;
if(racingwheel->HasHandbrake)
{
handbrake = reading.Handbrake; // returns a value between 0.0 and 1.0
}
if(racingwheel->HasClutch)
{
clutch = reading.Clutch; // returns a value between 0.0 and 1.0
}
讀取模式移位器
模式移位器是選擇性控件,提供以帶正負號整數值表示之 -1 與 MaxPatternShifterGear 之間的數位讀取。 值 -1 或 0 分別對應至 倒車 和 空檔 齒輪;正值逐漸增加,對應到更高的前進檔齒輪,直至 MaxPatternShifterGear,包含在內。 模式移位器的值是從 RacingWheelReading 結構 PatternShifterGear 属性讀取。
if (racingwheel->HasPatternShifter)
{
gear = reading.PatternShifterGear;
}
備註
支援的模式換檔與必要的 上一個齒輪 和 下一個齒輪 按鈕一起存在,這也會影響玩家汽車目前的齒輪。 一個簡單的策略來統一這些輸入是:當玩家選擇其汽車的自動變速器時,忽略模式切換器(和離合器);而當玩家選擇手動變速器時,只有當他們的賽車方向盤配備模式切換控件時,才忽略 上一個 和 下一變速 按鈕。 如果這不適合您的遊戲,您可以實作不同的統一策略。
執行 InputInterfacing 範例
GitHub 上的 InputInterfacingUWP 範例應用程式示範如何使用賽車遊戲方向盤和不同類型的輸入設備,以及這些輸入裝置作為 UI 導航控制器時的行為。
力回饋概觀
許多賽車方向盤都有強制反饋功能,可提供更身臨其境且更具挑戰性的駕駛體驗。 支持力回饋的賽車方向盤通常配備單一馬達,該馬達會沿著方向盤旋轉軸施加力。 Windows 10 或 Windows 11 和 Xbox One UWP 應用程式可透過 Windows.Gaming.Input.ForceFeedback 命名空間支援力回饋。
備註
力回饋 API 能夠支援數個力軸,但目前沒有賽車方向盤支援除方向盤旋轉以外的任何回饋軸。
使用力回饋
這些章節說明賽車方向盤程式設計強制反饋效果的基本概念。 反饋是藉由效果來套用,這些效果會先載入到力回饋裝置上,然後可以像音效一樣被啟動、暫停、繼續和停止;不過,您必須先確定賽車方向盤的回饋能力。
判斷強制意見反應功能
您可以藉由讀取賽車方向盤的 WheelMotor 屬性,判斷連接的賽車方向盤是否支持強制回饋。 如果 WheelMotor
是 null,則不支持力回饋;否則,支持力回饋,您可以繼續判斷馬達的具體回饋功能,例如可能會影響的軸。
if (racingwheel->WheelMotor != nullptr)
{
auto axes = racingwheel->WheelMotor->SupportedAxes;
if(ForceFeedbackEffectAxes::X == (axes & ForceFeedbackEffectAxes::X))
{
// Force can be applied through the X axis
}
if(ForceFeedbackEffectAxes::Y == (axes & ForceFeedbackEffectAxes::Y))
{
// Force can be applied through the Y axis
}
if(ForceFeedbackEffectAxes::Z == (axes & ForceFeedbackEffectAxes::Z))
{
// Force can be applied through the Z axis
}
}
載入力回饋效果
強制回饋效果會載入到回饋裝置上,其中在您的遊戲指令下自動「播放」。 提供了一些基本效果;自定義效果可以透過實作 IForceFeedbackEffect 介面的類別來建立。
效果類別 | 效果描述 |
---|---|
條件強制效果 | 可根據裝置內感測器的當前狀態施加可變力的效果。 |
常力效果 | 沿著向量施加恆定力的效果。 |
週期力效應 | 沿著向量套用由波形定義的變化的力作用。 |
斜坡力效果 | 套用沿著向量施加線性遞增/遞減力的效果。 |
using FFLoadEffectResult = ForceFeedback::ForceFeedbackLoadEffectResult;
auto effect = ref new Windows.Gaming::Input::ForceFeedback::ConstantForceEffect();
auto time = TimeSpan(10000);
effect->SetParameters(Windows::Foundation::Numerics::float3(1.0f, 0.0f, 0.0f), time);
// Here, we assume 'racingwheel' is valid and supports force feedback
IAsyncOperation<FFLoadEffectResult>^ request
= racingwheel->WheelMotor->LoadEffectAsync(effect);
auto loadEffectTask = Concurrency::create_task(request);
loadEffectTask.then([this](FFLoadEffectResult result)
{
if (FFLoadEffectResult::Succeeded == result)
{
// effect successfully loaded
}
else
{
// effect failed to load
}
}).wait();
使用力回饋效果
載入之後,所有效果可以透過在賽車方向盤的 WheelMotor
屬性上同步呼叫函式來啟動、暫停、恢復和停止,或也可以個別地直接呼叫回饋效果本身上的函式進行控制。 一般而言,您應該在遊戲開始之前將您想要使用的所有效果載入到意見反應裝置上,然後使用其各自的 SetParameters
功能,在遊戲進行時更新效果。
if (ForceFeedbackEffectState::Running == effect->State)
{
effect->Stop();
}
else
{
effect->Start();
}
最後,您可以根據需要,以非同步方式啟用、停用或重設特定賽車方向盤上的整個強制反饋系統。