Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
控制器、遊戲手把與搖桿
Godot 開箱即支援數百種控制器型號。控制器可在 Windows、macOS、Linux、Android、iOS 與 Web 上使用。
備註
自 Godot 4.5 起,引擎在 Windows、macOS 與 Linux 上的控制器支援改為依賴 SDL 3。這表示支援的控制器列表與行為,應與其他使用 SDL 3 的遊戲與引擎相當接近。請注意,SDL 僅用於輸入,不負責視窗或音效。
Prior to Godot 4.5, the engine used its own controller support code. This can cause certain controllers to behave incorrectly. This custom code is still used to support controllers on Android and Web, so it may result in issues appearing only on those platforms.
請注意,像方向盤、方向舵踏板及 HOTAS 這類更專業的裝置測試較少,可能無法完全依預期運作。這些裝置的力回饋覆寫功能也尚未實作。如果你有這類裝置,歡迎直接 在 GitHub 上回報問題 。
在本指南中,你將學到:
如何設計你的輸入邏輯以同時支援鍵盤與控制器輸入。
控制器與鍵盤/滑鼠輸入行為上的差異。
如何在 Godot 中排查控制器相關問題。
支援通用輸入
由於 Godot 的輸入動作系統,你可以同時支援鍵盤與控制器輸入,無需撰寫額外的分支程式碼。你應在「專案設定」中建立 輸入動作 ,這些動作可同時對應指定的鍵盤與控制器按鈕,避免在腳本中硬編碼按鍵或控制器按鈕。
詳細說明請參見 使用 InputEvent 頁面。
備註
與鍵盤輸入不同,若要支援滑鼠與控制器對同一動作(如第一人稱視角的環顧四周),這兩者必須分開處理,因此需要不同的程式邏輯。
我該用哪個 Input 單例的方法?
有三種取得類比輸入的方法:
當有兩個軸(如搖桿或 WASD 移動)且希望兩軸合為一個輸入時,請用
Input.get_vector():
# `velocity` will be a Vector2 between `Vector2(-1.0, -1.0)` and `Vector2(1.0, 1.0)`.
# This handles deadzone in a correct way for most use cases.
# The resulting deadzone will have a circular shape as it generally should.
var velocity = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
# The line below is similar to `get_vector()`, except that it handles
# the deadzone in a less optimal way. The resulting deadzone will have
# a square-ish shape when it should ideally have a circular shape.
var velocity = Vector2(
Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
Input.get_action_strength("move_back") - Input.get_action_strength("move_forward")
).limit_length(1.0)
// `velocity` will be a Vector2 between `Vector2(-1.0, -1.0)` and `Vector2(1.0, 1.0)`.
// This handles deadzone in a correct way for most use cases.
// The resulting deadzone will have a circular shape as it generally should.
Vector2 velocity = Input.GetVector("move_left", "move_right", "move_forward", "move_back");
// The line below is similar to `get_vector()`, except that it handles
// the deadzone in a less optimal way. The resulting deadzone will have
// a square-ish shape when it should ideally have a circular shape.
Vector2 velocity = new Vector2(
Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"),
Input.GetActionStrength("move_back") - Input.GetActionStrength("move_forward")
).LimitLength(1.0);
當你有單一軸可雙向移動(如飛行搖桿的油門),或要個別處理不同軸時,請用
Input.get_axis():
# `walk` will be a floating-point number between `-1.0` and `1.0`.
var walk = Input.get_axis("move_left", "move_right")
# The line above is a shorter form of:
var walk = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
// `walk` will be a floating-point number between `-1.0` and `1.0`.
float walk = Input.GetAxis("move_left", "move_right");
// The line above is a shorter form of:
float walk = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left");
對於其他類型的類比輸入,如扳機鍵或僅單方向輸入,請用
Input.get_action_strength():
# `strength` will be a floating-point number between `0.0` and `1.0`.
var strength = Input.get_action_strength("accelerate")
// `strength` will be a floating-point number between `0.0` and `1.0`.
float strength = Input.GetActionStrength("accelerate");
對於非類比的數位/布林輸入(僅有「按下」或「未按」),例如控制器按鈕、滑鼠按鍵或鍵盤鍵,請用 Input.is_action_pressed():
# `jumping` will be a boolean with a value of `true` or `false`.
var jumping = Input.is_action_pressed("jump")
// `jumping` will be a boolean with a value of `true` or `false`.
bool jumping = Input.IsActionPressed("jump");
備註
若你想判斷某輸入是否在上一個影格中『剛剛』被按下,請用 Input.is_action_just_pressed() 取代 Input.is_action_pressed()。後者在持續按下時會一直回傳 true,而 Input.is_action_just_pressed() 僅會在按下後的單一影格回傳 true。
振動
振動(也稱為*觸覺回饋*)能增強遊戲體驗。例如,在賽車遊戲中,可以用振動表現車輛行駛路面的不同,或在撞擊時產生強烈震動。
使用 Input 單例的 start_joy_vibration 方法可啟動手把振動。要提前停止(若啟動時未設定時長),則用 stop_joy_vibration。
在行動裝置上,可用 vibrate_handheld 讓整台裝置振動(獨立於手把)。Android 匯出前需於預設設定中勾選 VIBRATE 權限。
備註
部分玩家可能會排斥振動。請務必在遊戲中提供調整強度或關閉振動的選項。
鍵盤/滑鼠與控制器輸入的差異
如果你習慣只處理鍵盤與滑鼠輸入,控制器在某些情境下的行為可能會讓你感到驚訝。
死區
與鍵盤和滑鼠不同,控制器的軸是*類比*輸入。類比輸入的好處是能提供 0.0 到 1.0 的任意強度,數位輸入則只能有 0.0 或 1.0。但缺點是,若沒有死區設計,類比軸的值永遠不會精確等於 0.0,而會維持在如 0.062 這樣的低值,這種現象稱為*漂移*,在老舊或有缺陷的手把上更明顯。
以賽車遊戲為例:有了類比輸入,我們能讓車輛緩慢轉向。但若無死區,車輛即使玩家沒碰搖桿,也會自己慢慢轉彎,因為軸向強度不會真的歸零。因此我們通常設定死區(如 0.2),忽略小於此強度的輸入。理想的死區要高到能排除漂移影響,但又不會太高而誤判玩家的真實操作。
Godot 內建死區系統來解決這個問題。預設值為 0.5,但你可以在「專案設定」的「輸入對應」分頁中,針對每個動作調整死區。對於 Input.get_vector(),可指定第 5 個參數為死區值,若未指定則會取所有動作的平均死區值。
「重複」事件
與鍵盤不同,長按手把的按鈕(如方向鍵)**不會**產生固定間隔的重複輸入事件(即「重複」事件),因為作業系統對控制器輸入本就不會傳送這類事件。
若你要讓控制器按鈕也產生重複事件,需用程式自行產生 InputEvent 物件,並定時用 Input.parse_input_event() 解析。你可以配合 Timer 節點達成此效果。
視窗焦點
Unlike keyboard input, controller inputs can by default be seen by all windows on the operating system, including unfocused windows.
這對於 第三方分割畫面功能 很有幫助,但也可能有負面影響:玩家在操作其他視窗時,仍可能誤觸並將控制器輸入傳送到正在執行的專案。
If you wish to ignore controller input events when the project isn't focused,
set ProjectSettings.input_devices/joypads/ignore_joypad_on_unfocused_application to true.
Alternatively, you can also set Input.ignore_joypad_on_unfocused_application to true.
防止省電
與鍵盤與滑鼠不同,控制器輸入**不會**阻止作業系統進入睡眠或省電(如螢幕逾時自動關閉)。
因此 Godot 在專案執行時會自動啟用防止省電。如果你發現用手把遊玩時螢幕還是被關閉,請檢查「專案設定」裡 顯示 > 視窗 > 節能 > 保持螢幕開啟 是否已啟用。
疑難排解
也參考
你可以在 GitHub 上查看 控制器支援相關已知問題列表。
Godot 無法辨識我的控制器。
首先,確認你的控制器能被其他應用程式辨識。你可以使用 Gamepad Tester 網站來確認控制器是否被辨識。
在 Windows 上,Godot 一次僅支援最多 4 支控制器。這是因為 Godot 採用 XInput API,而此 API 最多只支援 4 支控制器。超過此數量的控制器將會被忽略。
我的控制器在某些平台可用,但在其他平台卻不可用。
Linux
若你用自行編譯的引擎執行檔,請確認已啟用 udev 支援(預設為開啟),不然在 SCons 編譯時加入 udev=no 會導致關閉。若用的是 Linux 發行版自帶的執行檔,也請確認其是否有啟用 udev。
控制器即使沒 udev 支援仍有機會運作,但穩定性較差,因為無法即時偵測熱插拔,只能定時輪詢檢查連接變化。
Android
如本文開頭所述,行動平台上的控制器支援是透過自訂實作而非使用 SDL 輸入。這表示其穩定度可能不如桌面平台。
Support for SDL-based controller input on mobile platforms is planned in a future release.
Web
Web 平台的控制器支援通常不如「原生」平台穩定,各瀏覽器間的支援品質差異很大。因此,若玩家無法使控制器正常運作,可能需要請他們改用其他瀏覽器。
Like for mobile platforms, support for SDL-based controller input on the web platform is planned in a future release.