此頁面說明如何使用 Windows.Gaming.Input.FlightStick 與通用 Windows 平台(UWP)的相關 API 來為 Xbox One 認證的飛行搖桿進行程式設計的基本概念。
閱讀此頁面後,您將瞭解:
- 如何收集飛行搖桿及其使用者的連線清單
- 如何偵測飛行搖桿是否已新增或移除
- 如何從一或多個飛行搖桿讀取輸入
- 飛行控制桿作為UI導航設備的行為表現如何
概觀
飛行杆是遊戲輸入設備,因能夠重現飛機或宇宙飛船駕駛艙中飛行杆的操作感而受到重視。 它們是完美的輸入設備,可快速準確地控制飛行。 飛行搖桿在 Windows 10 或 Windows 11 和 Xbox One 應用程式中均可透過 Windows.Gaming.Input 命名空間獲得支援。
Xbox One 認證的飛行棒配備下列控件:
- 可旋轉的模擬操縱桿,能夠翻滾、俯仰和偏航
- 類比油門
- 兩個發射按鈕
- 8 向帽形數位開關
- 檢視 和 選單 按鈕
備註
檢視 和 功能表 按鈕是用來支援 UI 導航,而不是用於遊戲命令,因此不能輕易地作為遊戲桿按鈕來存取。
使用者介面導覽
為了減輕為使用者介面瀏覽支援不同輸入裝置的負擔,並鼓勵遊戲與裝置之間的一致性,大多數
身為UI導航控制器,飛行桿會將導航命令 所需的
導航命令 | 飛行搖桿輸入 |
---|---|
向上 | 遊戲桿向上移動 |
向下 | 遊戲桿向下移動 |
左側 | 左側遊戲桿 |
正確 | 搖桿向右 |
查看 | 檢視 按鈕 |
菜單 | 選單 按鈕 |
接受 | FirePrimary 按鈕 |
取消 | FireSecondary 按鈕 |
飛行桿不會對應瀏覽命令的任何 選擇性集合。
偵測和追蹤飛行搖桿
偵測和追蹤飛行搖桿的運作方式與遊戲控制器完全相同,只是使用 FlightStick 類別,而非使用 Gamepad 類別。 如需詳細資訊,請參閱 遊戲手柄和震動。
閱讀飛行搖桿
識別您感興趣的飛行操作杆之後,即可準備從中收集信號。 不過,不同於您可能習慣的其他類型輸入裝置,飛行搖桿不會透過觸發事件來傳達狀態變更。 那麼,您會藉由 輪詢 來定期監測它們的目前狀態。
採樣飛行搖桿
輪詢會在精確的時間點擷取操縱桿的快照。 這種輸入收集方法最適合大部分的遊戲,因為它們的邏輯通常會在決定性循環中執行,而不是事件驅動。 從一次性收集的所有輸入解釋遊戲指令,通常比從一段時間內收集的多個單個輸入更簡單。
您可以呼叫 FlightStick.GetCurrentReading來查詢飛行杆。 此函式會傳回包含飛行桿狀態的 FlightStickReading。
下列範例會查詢飛行搖桿的當前狀態:
auto flightStick = myFlightSticks->GetAt(0);
FlightStickReading reading = flightStick->GetCurrentReading();
除了飛行搖桿狀態之外,每個讀取都包含時間戳,精確指出狀態被擷取的時間。 時間戳適用於與先前讀取的時間或遊戲仿真的時間相關。
讀取遊戲桿和節流輸入
控制桿在 X、Y 和 Z 軸上提供-1.0 至 1.0 之間的模擬讀數(分別為滾轉、俯仰和偏航)。 若為 roll,數值為 -1.0 會對應到搖桿的最左邊位置,而數值為 1.0 則對應到最右邊位置。 對於俯仰,值為 -1.0 對應到搖桿的最下方位置,而值為 1.0 對應到搖桿的最上方位置。 若為 yaw,值為 -1.0 會對應到最逆時針、扭曲的位置,而 1.0 的值則對應至最順時針的位置。
在所有座標軸中,當遊戲桿位於中心位置時,值大約是0.0,但即使在後續的讀數中,精確值的變化也是正常的。 本節稍後將討論緩和此變化的策略。
遊戲桿的滾動值是從 FlightStickReading.Roll 属性讀取,音調的值是從 FlightStickReading.Pitch 属性讀取,而 yaw 的值則會從 FlightStickReading.Yaw 属性讀取:
// Each variable will contain a value between -1.0 and 1.0.
float roll = reading.Roll;
float pitch = reading.Pitch;
float yaw = reading.Yaw;
讀取遊戲桿值時,您會發現當遊戲桿在中央位置待用時,它們不會可靠地產生 0.0 的中性讀數:相反地,每次移動遊戲桿並返回中心位置時,它們都會產生接近0.0的不同值。 若要減輕這些變化,您可以實作小型 死區,這是忽略的理想中心位置附近的值範圍。
實作死區的方法之一是判斷遊戲桿從中央移動的距離,並忽略比您選擇的距離更近的讀數。 您可以大致計算距離,但它不精確,因為搖桿讀數基本上是極座標值,而不是平面值,只需使用畢達哥拉斯定理即可。 這會產生星形死區。
下列範例示範使用畢氏定理的基本圓形死區:
// Choose a deadzone. Readings inside this radius are ignored.
const float deadzoneRadius = 0.1f;
const float deadzoneSquared = deadzoneRadius * deadzoneRadius;
// Pythagorean theorem: For a right triangle, hypotenuse^2 = (opposite side)^2 + (adjacent side)^2
float oppositeSquared = pitch * pitch;
float adjacentSquared = roll * roll;
// Accept and process input if true; otherwise, reject and ignore it.
if ((oppositeSquared + adjacentSquared) < deadzoneSquared)
{
// Input accepted, process it.
}
讀取按鈕和帽子開關
飛行操縱桿上的兩個發射按鈕,每個按鈕都提供數位信號,指示其是否被按下(向下)或鬆開(向上)。 為了提高效率,按鈕讀數不會以個別布爾值表示,而是全部封裝成單一位域,這些位域由 FlightStickButtons 列舉表示。 此外,8 向帽形開關提供的方向被打包成單一位元欄位,並由 GameControllerSwitchPosition 列舉表示。
備註
飛行杆配備額外的按鈕,用於UI導覽,例如 檢視 和 選單 按鈕。 這些按鈕不是 FlightStickButtons
列舉的一部分,只能透過將飛行搖桿作為UI導航裝置來讀取。 如需詳細資訊,請參閱 UI 瀏覽控制器。
按鈕值會從 FlightStickReading.Buttons 屬性讀取。 由於此屬性是位元欄位,因此會使用位元遮罩來隔離您感興趣的按鈕值。 當對應的位元被設定時,按鈕被按下(向下);否則,按鈕被釋放(向上)。
下列範例會判斷 FirePrimary 按鈕是否被按下:
if (FlightStickButtons::FirePrimary == (reading.Buttons & FlightStickButtons::FirePrimary))
{
// FirePrimary is pressed.
}
下列範例會判斷 FirePrimary 按鈕是否被放開:
if (FlightStickButtons::None == (reading.Buttons & FlightStickButtons::FirePrimary))
{
// FirePrimary is released (not pressed).
}
有時候,您可能希望判斷按鈕從按下轉變到放開或從放開轉變到按下的狀態,是否有多個按鈕被按下或放開,或是判斷一組按鈕是否以某特定方式排列,即部分按下,部分未按下。 如需如何偵測每個條件的資訊,請參閱 偵測按鈕轉換 和 偵測複雜按鈕排列。
帽開關值是從 FlightStickReading.HatSwitch 屬性讀取。 由於這個屬性也是位欄位,因此會再次使用位元運算遮罩來隔離帽子開關的位置。
以下範例用來判斷帽子開關是否處於向上的位置:
if (GameControllerSwitchPosition::Up == (reading.HatSwitch & GameControllerSwitchPosition::Up))
{
// The hat switch is in the up position.
}
下列範例會判斷方向帽開關是否位於中央:
if (GameControllerSwitchPosition::Center == (reading.HatSwitch & GameControllerSwitchPosition::Center))
{
// The hat switch is in the center position.
}