輸入範例

前言

本教學將帶你學習如何使用 Godot 的 InputEvent 系統來捕捉玩家輸入。你的遊戲可能會用到多種不同的輸入類型——例如鍵盤、手把、滑鼠等等——以及各種將這些輸入轉換為遊戲行動的方法。本文將介紹一些最常見的情境,幫助你作為自己專案的起點。

備註

若想進一步了解 Godot 輸入事件系統的運作方式,請參閱 使用 InputEvent

事件與輪詢

有時你會希望遊戲對特定輸入事件有反應——像是按下「跳躍」鍵。其他時候,你可能希望只要某個按鍵有被按住(例如移動),就持續發生某些動作。第一種情況可以使用 _input() 方法,當有輸入事件發生時會自動呼叫;第二種情況則可利用 Input 單例來查詢輸入狀態。

範例:

func _input(event):
    if event.is_action_pressed("jump"):
        jump()


func _physics_process(delta):
    if Input.is_action_pressed("move_right"):
        # Move as long as the key/button is pressed.
        position.x += speed * delta

這讓你可以更加彈性地混合處理不同類型的輸入方式。

接下來的教學將著重於用 _input() 捕捉單一事件。

輸入事件

輸入事件是繼承自 InputEvent 的物件。根據事件型別,物件會包含該事件專屬的屬性。若要觀察事件本體,請新增一個節點並掛上以下腳本:

extends Node


func _input(event):
    print(event.as_text())

當你按下按鍵、移動滑鼠或進行其他輸入時,所有事件都會在輸出視窗中依序顯示。以下是範例輸出:

A
Mouse motion at position ((971, 5)) with velocity ((0, 0))
Right Mouse Button
Mouse motion at position ((870, 243)) with velocity ((0.454937, -0.454937))
Left Mouse Button
Mouse Wheel Up
A
B
Shift
Alt+Shift
Alt
Shift+T
Mouse motion at position ((868, 242)) with velocity ((-2.134768, 2.134768))

如你所見,不同類型的輸入有著完全不同的事件內容。鍵盤事件甚至會直接列印對應的按鍵符號。例如,InputEventMouseButton 就繼承自以下類別:

小訣竅

建議在處理事件時隨時參考官方類別說明,方便查詢各型別事件可用的屬性與方法。

如果你嘗試存取某個輸入型別沒有的屬性(例如在 InputEventKey 上取用 position),會發生錯誤。為避免這種情況,請務必先檢查事件型別:

func _input(event):
    if event is InputEventMouseButton:
        print("mouse button event at ", event.position)

輸入映射表

InputMap 是處理多元輸入的最彈性方式。你可以建立具名的輸入「動作」,並將多組輸入事件(如按鍵、滑鼠點擊等)對應到這些動作。要查看和新增自訂動作,請進入「專案」→「專案設定」,點選「InputMap」分頁:

../../_images/inputs_inputmap.webp

小訣竅

新的 Godot 專案會預先定義許多內建動作。若要檢視這些動作,請在 InputMap 對話視窗中啟用「Show Built-in Actions」(顯示內建動作)。

處理動作

定義好動作後,你可以在腳本中用 is_action_pressed()is_action_released() 這兩個方法,傳入動作名稱來判斷動作是否觸發:

func _input(event):
    if event.is_action_pressed("my_action"):
        print("my_action occurred!")

鍵盤事件

鍵盤事件會以 InputEventKey 型別捕捉。雖然建議盡量改用輸入動作,但有時你可能需要直接判斷個別按鍵。以下為偵測 T 按鍵的範例:

func _input(event):
    if event is InputEventKey and event.pressed:
        if event.keycode == KEY_T:
            print("T was pressed")

小訣竅

請參考 @GlobalScope_Key 取得按鍵常數列表。

警告

由於 鍵盤鬼影現象(ghosting),如果同時按下太多按鍵,部分按鍵輸入可能不會被正確偵測。根據按鍵在鍵盤上的位置,有些按鍵更容易發生鬼影現象。有些鍵盤具備硬體層級的抗鬼影(anti-ghosting)功能,但低價鍵盤和筆電鍵盤通常沒有這項設計。

因此,建議設計預設鍵位配置時,需考慮到一般鍵盤(無抗鬼影功能)也能正常使用。詳情可參考 這則 Gamedev Stack Exchange 問題

鍵盤修飾鍵

修飾鍵屬性繼承自 InputEventWithModifiers,你可以用布林值檢查修飾鍵組合。假如你希望單獨按下 T 和按下 Shift + T 會有不同反應,可以這樣寫:

func _input(event):
    if event is InputEventKey and event.pressed:
        if event.keycode == KEY_T:
            if event.shift_pressed:
                print("Shift+T was pressed")
            else:
                print("T was pressed")

小訣竅

請參考 @GlobalScope_Key 取得按鍵常數列表。

滑鼠事件

滑鼠事件繼承自 InputEventMouse,並細分為 InputEventMouseButtonInputEventMouseMotion 兩種型別。也就是說,所有滑鼠事件都會帶有 position 屬性。

滑鼠按鈕

滑鼠按鈕的捕捉方式與鍵盤事件非常類似。@GlobalScope_MouseButton 內含所有可用滑鼠按鈕的 MOUSE_BUTTON_* 常數,對應到事件的 button_index 屬性。注意,滑鼠滾輪也算按鈕(嚴格來說是二個),分別為 MOUSE_BUTTON_WHEEL_UPMOUSE_BUTTON_WHEEL_DOWN,會分成不同事件。

func _input(event):
    if event is InputEventMouseButton:
        if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
            print("Left button was clicked at ", event.position)
        if event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed:
            print("Wheel up")

滑鼠移動

每當滑鼠移動時,都會產生 InputEventMouseMotion 事件。可以透過 relative 屬性取得移動的距離。

以下為使用滑鼠事件拖曳 Sprite2D 節點的範例:

extends Node


var dragging = false
var click_radius = 32 # Size of the sprite.


func _input(event):
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
        if (event.position - $Sprite2D.position).length() < click_radius:
            # Start dragging if the click is on the sprite.
            if not dragging and event.pressed:
                dragging = true
        # Stop dragging if the button is released.
        if dragging and not event.pressed:
            dragging = false

    if event is InputEventMouseMotion and dragging:
        # While dragging, move the sprite with the mouse.
        $Sprite2D.position = event.position

觸控事件

如果你使用觸控螢幕裝置,會產生觸控事件。InputEventScreenTouch 相當於滑鼠點擊事件,而 InputEventScreenDrag 則與滑鼠移動事件相似。

小訣竅

若想在非觸控螢幕裝置上測試觸控事件,請於專案設定 > Input Devices/Pointing 區段中,啟用「Emulate Touch From Mouse」(滑鼠模擬觸控)。這樣專案就會將滑鼠點選與移動視為觸控事件。