Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

控制器、手柄和搖桿

Godot支援數百種控制器模型,這要歸功於社區提供的 SDL遊戲控制器資料庫

控制器支援Windows、macOS、Linux、Android、iOS和HTML5。

請注意,諸如方向盤、方向盤踏板和 HOTAS 等更專業的裝置測試較少,可能並不總是按照預期工作。目前尚未實作在這些裝置上的力回饋覆蓋。如果你有機會使用這些裝置,請不要猶豫,在 GitHub 上報告錯誤。

在本指南中,我們將學到:

  • 如何編寫你的輸入邏輯,從而支援鍵盤和控制器輸入。

  • 控制器的行為如何與鍵盤/滑鼠輸入不同。

  • 解決 Godot 中控制器的問題。

為通用 Windows 平台(UWP) 匯出

得益於 Godot 的輸入動作系統,Godot 可以同時支援鍵盤和控制器輸入,而不需要編寫單獨的程式碼路徑。你不應該在腳本中對控制器的按鍵進行硬編碼,應該在專案設定中建立*輸入動作*,這些動作引用按鍵和控制器輸入。

輸入動作在 使用 InputEvent 頁面上有詳細解釋。

備註

與鍵盤輸入不同,支援滑鼠和控制器輸入的動作將需要不同的程式碼路徑,例如在第一人稱遊戲中四處查看,因為這些必須被分開處理。

GDScript是什麼?為什麼我要用它?

有3種方式可以以類比感知的方式獲得輸入:

  • 當你有兩個軸,如操縱桿或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)
  • 當你有一個軸可以雙向移動時,比如飛行操縱桿上的油門,或者你想單獨處理不同的軸時,使用 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")
  • 對於其他型別的模擬輸入,例如處理一個觸發器或一次處理一個方向,使用 Input.get_action_strength() :

# `strength` will be a floating-point number between `0.0` and `1.0`.
var strength = Input.get_action_strength("accelerate")

對於非類比數位/布林輸入(只有 "按下 " 或 "未按下 " 的值),如控制器按鈕、滑鼠按鈕或鍵盤按鍵,使用 Input.is_action_pressed() :

# `jumping` will be a boolean with a value of `true` or `false`.
var jumping = Input.is_action_pressed("jump")

備註

如果您需要知道某個輸入是否在前一影格中「剛剛」被按下,請使用「Input.is_action_just_pressed()」而不是「Input.is_action_pressed()」。與只要保持輸入就回傳 true 的「Input.is_action_pressed()」不同,「Input.is_action_just_pressed()」只會在按鈕按下後一影格返回「true」按下。

在3.4之前的Godot版本,如3.3, Input.get_vector()Input.get_axis() 不可用。只有 Input.get_action_strength()Input.is_action_pressed() 在Godot 3.3中可用。

減法

振動(也稱為*觸覺回饋*)可用於增強遊戲的感覺。例如,在賽車遊戲中,您可以透過振動傳達汽車目前行駛的表面,或在碰撞時產生突然的振動。

使用輸入單例的 start_joy_vibration<class_Input_method_start_joy_vibration>` 方法開始振動遊戲手把。使用 stop_joy_vibration<class_Input_method_stop_joy_vibration>` 提前停止振動(如果啟動時未指定持續時間,則很有用)。

在行動裝置上,您也可以使用 vibrate_handheld<class_Input_method_vibrate_handheld> 來振動裝置本身(獨立於遊戲手把)。在 Android 上,這需要在匯出專案之前在 Android 匯出預設中啟用「VIBRATE」權限。

備註

振動可能會讓某些玩家感到不舒服。確保提供遊戲內滑桿來停用振動或降低其強度。

鍵盤/滑鼠和控制器輸入之間的差異

如果您習慣於處理鍵盤和滑鼠輸入,可能會對控制器處理特定情況的方式感到驚訝。

死區

與鍵盤和滑鼠不同,控制器提供帶有*模擬*輸入的軸。模擬輸入的好處是它們為動作提供了額外的靈活性。不像數位輸入只能提供 0.01.0 的強度,模擬輸入可以提供 0.01.0 之間的*任何*強度。缺點是沒有死區系統,由於控制器的物理結構,類比軸的強度永遠不會等於 0.0。相反,它將徘徊在一個低值,如 0.062。這種現象被稱為*漂移*,在舊的或有問題的控制器上會更加明顯。

讓我們把賽車遊戲作為一個現實世界的例子。由於有了模擬輸入,我們可以將汽車慢慢地轉向一個或另一個方向。然而,如果沒有死區系統,即使玩家不接觸操縱桿,汽車也會自己慢慢轉向。這是因為方向軸的強度在我們期望的時候不會等於 0.0。因為我們不希望我們的車在這種情況下自動轉向,我們定義了一個“死區”值 0.2,它將忽略所有強度低於 0.2 的輸入。一個理想的死區值是足夠高的,可以忽略操縱桿漂移引起的輸入,但又足夠低,不會忽略玩家的實際輸入。

Godot 有一個內建的死區系統來解決這個問題。預設值是 0.2,但你可以在“專案設定”的“按鍵對應”分頁中根據每個動作增加或減少它。對於 Input.get_vector(),可以指定死區,否則它將從向量中的所有動作計算出平均死區值。

“回聲”事件

與鍵盤輸入不同,按住一個控制器按鈕,如十字方向鍵,**不會**產生固定間隔的重複輸入事件(也被稱為“回聲”事件)。這是因為作業系統首先不會為控制器輸入發送“回聲”事件。

如果你想讓控制器按鈕發送回聲事件,你將不得不通過程式碼生成 InputEvent 物件,並使用 Input.parse_input_event() 定期解析它們。這可以在 Timer 節點的幫助下完成。

Windows

與鍵盤輸入不同,作業系統上的**所有**視窗都可以看到控制器輸入,包括未聚焦的視窗。

雖然這對於「第三方分割畫面功能 <https://nucleus-coop.github.io/>`__ 很有用,但它也可能產生不利影響。玩家在與另一個視窗互動時可能會意外地將控制器輸入傳送到正在執行的專案。

如果您希望在專案視窗未聚焦時忽略事件,則需要使用以下腳本建立名為「Focus」的自動載入 <doc_singletons_autoload>` 並使用它來檢查所有輸入:

# Focus.gd
extends Node

var focused := true

func _notification(what: int) -> void:
    match what:
        NOTIFICATION_APPLICATION_FOCUS_OUT:
            focused = false
        NOTIFICATION_APPLICATION_FOCUS_IN:
            focused = true


func input_is_action_pressed(action: StringName) -> bool:
    if focused:
        return Input.is_action_pressed(action)

    return false


func event_is_action_pressed(event: InputEvent, action: StringName) -> bool:
    if focused:
        return event.is_action_pressed(action)

    return false

然後,不要使用“Input.is_action_pressed(action)”,而是使用“Focus.input_is_action_pressed(action)”,其中“action”是輸入操作的名稱。另外,不要使用“event.is_action_pressed(action)”,而是使用“Focus.event_is_action_pressed(event, action)”,其中“event”是InputEvent引用,“action”是事件的名稱。輸入動作。

防止省電模式

與鍵盤和滑鼠輸入不同,控制器輸入**不會**抑制睡眠和省電措施(例如在經過一定時間後關閉螢幕)。

為了解決這個問題,Godot 在專案運作時預設啟用節能預防。如果您注意到系統在玩遊戲手把時關閉了顯示屏,請檢查專案設定中的 顯示 > 視窗 > 節能 > 保持螢幕開啟 的值。

在 Linux 上,節能預防要求引擎能夠使用 D-Bus。如果在 Flatpak 中運作專案,請檢查 D-Bus 是否已安裝且可存取,因為沙盒限制可能會導致預設無法實作此操作。

疑難排解

也參考

請瀏覽 GitHub 上的 HTML5 問題列表 以瞭解您有興趣的功能目前是否有問題。若列表上沒有,可以開啟 Issue 來與大家交流。

Godot 無法識別我的控制器。

首先,檢查你的控制器是否被其他應用程式識別。你可以使用 Gamepad Tester 網站來確認你的控制器被識別。

我的控制器的按鈕或軸對應不正確。

首先,如果您的控制器提供某種韌體更新實用程式,請確保運作它以從製造商處獲取最新修復程式。例如,Xbox One 和 Xbox Series 控制器可以使用「Xbox Accessories 應用程式 <https://www.microsoft.com/en-us/p/xbox-accessories/9nblggh30xj3>」更新其韌體。 (此應用程式僅在Windows 上執行,因此您必須使用Windows 電腦或支援USB 的Windows 虛擬機器來更新控制器的韌體。)更新控制器的韌體後,請取消控制器配對,然後再次將其與PC配對(如果您是這樣)在無線模式下使用控制器。

如果按鈕存在對應錯誤,可能是由於來自 `SDL 遊戲控制器資料庫 <https://github.com/gabomdq/SDL_GameControllerDB>`__的錯誤的對應。你可以在連結的倉庫中提交拉取請求,為下一個 Godot 版本提供對應更新。

有很多方法來建立對應。一個選擇是使用 官方Joypads演示 中的對應嚮導。一旦你有了控制器可工作的對應,你可以在運作Godot之前通過定義 SDL_GAMECONTROLLERCONFIG 環境變數來測試它:

export SDL_GAMECONTROLLERCONFIG="your:mapping:here"
./path/to/godot.x86_64

要在非桌面平臺上測試對應,或者用額外的控制器對應來分發你的專案,你可以通過呼叫 Input.add_joy_mapping() 儘早在腳本的 _ready() 函式中新增它們。

我的控制器在特定的平臺上工作,但在另一個平臺上卻不能。

Linux

如果您使用自編譯引擎二進位檔案,請確保它是使用 udev 支援進行編譯的。預設啟用此功能,但可以透過在 SCons 命令列上指定「udev=no」來停用 udev 支援。如果您使用的是 Linux 發行版提供的引擎二進位檔案,請仔細檢查它是否是使用 udev 支援進行編譯的。

控制器在沒有 udev 支援的情況下仍然可以工作,但可靠性較低,因為必須使用定期輪詢來檢查遊戲期間控制器的連接或斷開連接(熱插拔)。

HTML5

與 "本地" 平臺相比,HTML5 控制器的支援通常不太可靠。各個瀏覽器對控制器的支援品質往往相差甚遠。因此,如果玩家無法使用他們的控制器,你可能不得不指示他們使用不同的瀏覽器。