跳轉至內容

Godot 遊戲引擎指南/輸入

100% developed
來自華夏公益教科書,開放世界開放書籍

在每個遊戲中,你都可以按下按鈕或點選螢幕來執行操作。這被稱為對輸入做出反應。有兩種方法可以做到:使用輸入對映和手動方式。

輸入對映

[編輯 | 編輯原始碼]

轉到你的專案設定,在專案 -> 專案設定... 中點選輸入對映選項卡。你會看到一個輸入動作列表,例如 "ui_select"。這些是預設的動作,可以編輯,但不能刪除。

但是,你可以 - 也應該 - 建立你自己的輸入動作。在顯示 "動作:" 的地方,輸入一個動作名稱,例如 "射擊" 或 "前進"。按下它旁邊的 "新增" 按鈕。這將建立你的動作。

你會注意到它沒有關聯的輸入事件。按下你新建動作旁邊的 "+" 按鈕。你會看到以下選項:

  1. 鍵:允許你連結任何鍵盤按鈕。
  2. 搖桿按鈕:允許你連結手柄按鈕。
  3. 搖桿軸:允許你連結手柄搖桿運動。
  4. 滑鼠按鈕:允許你連結滑鼠按鈕。


對於觸控式螢幕和滑鼠移動,請參閱下面提到的手動輸入檢測部分。

有幾種方法可以檢測它們是否被按下,你選擇的方法取決於動作的用途。下面的函式返回一個布林值,除非另有說明,否則應放在 "if" 或 "while" 語句中。

函式 用途
is_action_pressed 可以按住的動作,例如移動或射擊自動武器
is_action_just_pressed 僅在按鈕按下時執行的動作,並且在動作釋放之前無法再次執行。
get_action_strength 移動,僅適用於搖桿(用於精確控制)。返回一個浮點數,1 = 搖桿完全傾斜或按下,0 = 搖桿未傾斜或未按下。
is_action_just_released 僅在釋放時執行的動作(例如,按鈕未按下)

以上方法都呼叫Input單例。它們都接受一個字串引數。

if Input.is_action_just_pressed("shoot"):
  pass # Add shooting code here

字串引數必須是輸入對映中定義的輸入動作的名稱。

手動輸入檢測

[編輯 | 編輯原始碼]

假設你想要檢測滑鼠移動或觸控式螢幕事件,或者輸入對映無法工作,因為你需要對無法保證使用者(或你自己)會建立輸入事件的工具進行輸入。

這時就需要手動輸入檢測。這就像使用伺服器。手動輸入檢測是輸入對映的低階等效項,它更復雜,但提供更多功能。

以下程式碼在移動滑鼠時移動一個 2D 精靈,並忽略所有其他輸入。

extends Sprite2D

func _input(event):
  if event is InputEventMouseMotion:
    position += event.relative

以下程式碼建立了一個簡單的按鈕。_gui_input() 僅適用於 Control 派生節點,並在以下情況下執行:如果該節點處於焦點狀態,並且你按下了鍵,你使用滑鼠按下鍵或滑鼠懸停在其上。

extends Control
signal button_up
signal button_down

var pressed = false

func _gui_input(event):
  if event is InputEventMouseButton and event.button_index == BUTTON_LEFT:
    if event.pressed:
      get_tree().set_input_as_handled()
      emit_signal("button_down")
      pressed = true
    elif not event.pressed:
      if pressed:
        emit_signal("button_up")
      pressed = false

get_tree().set_input_as_handled() 確保不會呼叫其他 _gui_input()_unhandled_input()

存在許多輸入事件。它們如下所示:

  • InputEventMouse
    • InputEventMouseButton:在你點選滑鼠按鈕時發出。使用以下方法讀取:button_index(BUTTON_* 常量),pressed。
    • InputEventMouseMotion:在你移動滑鼠時發出。使用以下方法讀取:relative(自上次呼叫輸入以來滑鼠移動了多少),position(滑鼠相對於遊戲視窗左上角的新位置 - 或 "_gui_input" 呼叫中的節點位置)。
  • InputEventKey:在你按下鍵盤上的按鈕時發出。使用以下方法讀取:button_index(KEY_* 常量),pressed,echo(如果為真,表示按鈕正在被按下)。
  • InputEventScreen
    • InputEventScreenTouch:在你點選螢幕時發出。使用以下方法讀取:position(你在螢幕上點選的位置),pressed(如果為假,表示你正在鬆開螢幕)。
    • InputEventScreenDrag:在你拖動螢幕時發出。使用以下方法讀取:position(新位置),relative(自上次輸入呼叫以來手指移動了多少),fingers。
  • InputEventJoy
    • InputEventJoyButton:對手柄按鈕按下發出。使用以下方法讀取:pressed,button_index(JOY_* 常量)。
    • InputEventJoyMotion:對手柄搖桿移動發出。使用以下方法讀取:position,relative。

更多資訊請參見:InputEvent 教程.

Input 單例

[編輯 | 編輯原始碼]

因此,讀取輸入非常有趣。但是,還有幾種更常用的輸入方法。在你繼續閱讀之前,嘗試思考一下它們是什麼?

除了使用輸入單例之外,還有更多方法,本節將深入解釋可以實現的功能以及如何實現。

動作控制

[編輯 | 編輯原始碼]

動作控制存在於許多流行遊戲中,特別是 VR 和/或 AR 遊戲中,用於環顧四周。

func _process():
  # Assume camera_pivot is a Spatial with a child Camera3D node.
  # The gyroscope only works when exported to Android.
  $camera_pivot.rotation += Input.get_gyroscope()
  # The accelerometer is only available when exported to mobile.
  # This makes you move the camera when you move the device (Not when you rotate it)
  $camera_pivot.rotation += Input.get_accelerometer()

這僅適用於 "旋轉" 動作檢測。

許多流行遊戲都包含振動。你可以在玩家受到攻擊時呼叫以下程式碼:

Input.vibrate_handheld(100)
Input.start_joy_vibration(0, .5, .4, 1.0)

這將使手柄或移動裝置振動 1 秒。

InputMap 單例

[編輯 | 編輯原始碼]

InputMap 允許透過程式碼建立輸入動作。這在玩家可以更改控制方案的遊戲中很有用。

有關 InputMap 的詳細介紹,請參見此處.

以下程式碼建立了一個射擊動作,它對應於按下空格鍵。

extends Node

func _ready():
  InputMap.add_action("shoot")
  InputMap.action_add_event("shoot", create_key_action(KEY_SPACE))

func create_key_action(key) -> InputEventKey:
  var input = InputEventKey.new()
  input.pressed = true
  input.scancode = key
  return input

它可以是任何輸入事件,不一定是 InputEventKey

有關建立 InputEvents 的更多資訊,請參見下面的 "偽造" 輸入部分。

其他有用方法

  1. load_from_globals(): 將動作重置為專案設定中設定的動作。
  2. has_action(action: String): 如果動作存在,則返回 true。
  3. action_erase_events(action: String): 清除動作,使其不再有任何關聯事件。
  4. erase_action(action: String): 刪除動作。

與往常一樣,這並非列出所有方法。只是一些方法。

音訊輸入

[編輯 | 編輯原始碼]

要錄製音訊,你需要執行兩項操作:

  1. 按下螢幕底部的 "音訊" 按鈕,然後按下 "新建匯流排"。將其重新命名為 "麥克風",然後點選 "新增效果"。在出現的下拉選單中按下 "錄製"。
  2. 為你的場景建立一個新的 AudioStreamPlayer 節點。在檢查器中點選值。從出現的下拉選單中選擇新建 AudioStreamMicrophone。將 "匯流排" 屬性設定為 "麥克風"。每當你想在遊戲中錄製音訊時,只需將 "播放" 值設定為 true 即可。

讀取音訊以進行語音識別等操作可以實現,但並不容易,超出了本書(以及作者知識)的範圍。

"偽造" 輸入

[編輯 | 編輯原始碼]

所以,你決定要在執行時更改 InputMap?但是該怎麼做呢?

Godot 有幾個強大的類,它們使輸入檢測更容易,並且可以偽造輸入。

更多資訊請參見:InputEvent 教程.

InputEventKey

[編輯 | 編輯原始碼]

InputEventKey 用於檢測鍵盤按鍵的按下和釋放。

以下程式碼允許你使用 A 鍵射擊

extends Node

func shoot_with_a():
  var input = InputEventKey.new()
  input.pressed = true
  input.scancode = KEY_A
  InputMap.action_erase_events("shoot")
  InputMap.action_add_event("shoot", input)

“Input.event_erase_actions” 清除為指定事件的所有操作。在這種情況下,空格鍵將不再讓你射擊。

可以指定任何鍵,儘管可能不清楚如何做到這一點。

鍵常量
常量 關於
KEY_<letter> 字母鍵
KEY_<number> 數字鍵
KEY_KP_MULTIPLY 小鍵盤上的 *
KEY_KP_DIVIDE 小鍵盤上的 /
KEY_KP_SUBTRACT 小鍵盤上的 -
KEY_KP_ADD 小鍵盤上的 +
KEY_KP_ENTER 小鍵盤上的 Enter
KEY_KP_PERIOD 小鍵盤上的 .
KEY_SPACE 空格
KEY_ENTER 回車
KEY_PLUS +
KEY_MINUS -
KEY_EQUALS =
KEY_QUESTION ?
KEY_EXCLAIM !
KEY_QUOTEDBL "
KEY_NUMBERSIGN #
KEY_DOLLAR $
KEY_PERCENT %
KEY_AMPERSAND &
KEY_APOSTROPHE '
KEY_PARENLEFT (
KEY_PARENRIGHT )
KEY_AT @
KEY_COLON :
KEY_SEMICOLON ;
KEY_GREATER >
KEY_LESS <
KEY_BRACKETLEFT [
KEY_BRACKETRIGHT ]
KEY_BACKSLASH \
KEY_ASCIICIRCUM ^
KEY_UNDERSCORE _
KEY_QUOTELEFT `
KEY_BRACELEFT {
KEY_BRACERIGHT }
KEY_BAR |
KEY_ASCIITIDLE ~
KEY_STERLING £
KEY_CENT ¢
KEY_YEN ¥
KEY_COPYRIGHT ©
KEY_REGISTERED ®
KEY_UP 向上 箭頭鍵
KEY_DOWN 向下 箭頭鍵
KEY_LEFT 向左 箭頭鍵
KEY_RIGHT 向右 箭頭鍵
KEY_TAB Tab
KEY_BACKTAB Shift + Tab 鍵同時按下
KEY_ESCAPE Esc
KEY_DELETE 刪除
KEY_INSERT 插入
KEY_BACK 退格
KEY_SHIFT Shift
KEY_ALT Alt
KEY_CONTROL Ctrl 鍵(僅限 Windows)
KEY_META Meta 鍵(僅限 Linux)
KEY_F<number 1 to 12> 鍵盤上的 F1 等鍵
KEY_COMMA ,
KEY_PERIOD .
KEY_ASTERISK *
KEY_SLASH /
KEY_HOME Home
KEY_PAUSE 暫停
KEY_PRINT Print Screen
KEY_CLEAR 清除
KEY_END End
KEY_SYSREQ 系統請求
KEY_PAGEUP Page Up
KEY_PAGEDOWN Page Down
KEY_NUMLOCK Num Lock
KEY_SCROLLLOCK Scroll Lock
KEY_CAPSLOCK Caps Lock
KEY_MENU 上下文選單
KEY_HELP 幫助
KEY_BACK 媒體後退 鍵。不要與 Android 裝置上的後退按鈕混淆
KEY_FORWARD 媒體前進
KEY_STOP 媒體停止
KEY_MEDIAPLAY 媒體播放

如果你想檢測某些修飾符是否也被按下,你可以訪問這些變數

  1. alt: 如果必須按下鍵盤上的“Alt”,則設定為 true。
  2. ctrl: 如果必須按下鍵盤上的“Ctrl”(僅限 Windows),則設定為 true。
  3. meta: 如果必須按下鍵盤上的“Meta”(僅限 Linux),則設定為 true。
  4. command: 如果必須按下鍵盤上的“Ctrl”(在 Windows 上)或“Meta”(在 Linux 上),則設定為 true。
  5. shift: 如果必須按下鍵盤上的“shift”,則設定為 true。

你可以將其中多個設定為 true。這將使你需要按下所有設定的修飾符。

如果你想檢測釋放鍵而不是按下鍵,不要將“pressed”設定為 true。如果將其新增到 InputMap,它將在其鍵未按下時始終保持按下狀態,但只有在它們第一次釋放後才會發生。那麼如何解決這個問題呢?實際上,這很簡單!

試試 Input.event_<press/release>("shoot")。它工作得很好,但是如果你需要在 _input 的呼叫中使用它,你應該改用 Input.parse_input_event(event)

InputEventMouse

[編輯 | 編輯原始碼]

檢測滑鼠輸入或模擬滑鼠輸入可以用兩種方式解釋:滑鼠按鈕和滑鼠移動。

另請參閱:滑鼠和輸入座標教程.

InputEventMouseButton

[編輯 | 編輯原始碼]

點選滑鼠是一個常見的操作,但模擬它並不常見。它是最簡單的閱讀和模擬的操作,只需要 2 個值。

extends Node

func shoot_on_click():
  var input = InputEventMouseButton.new()
  input.pressed = true
  input.button_index = BUTTON_LEFT
  InputMap.action_erase_events("shoot")
  InputMap.action_add_event("shoot",input)
變數
變數 用途
doubleclick 如果為 true,則該按鈕被雙擊。
factor 事件的係數(或增量),以浮點數表示。在用於高精度滾動事件時,這表示滾動量。僅在某些平臺上受支援。如果當前平臺不支援,則可能為 0
button_index 的允許值
常量 含義
BUTTON_LEFT 左鍵單擊
BUTTON_RIGHT 右鍵單擊
BUTTON_MIDDLE 滾動按鈕按下
BUTTON_WHEEL_UP 向上滾動滾輪。
BUTTON_WHEEL_DOWN 向下滾動滾輪。

InputEventMouseMotion

[編輯 | 編輯原始碼]

模擬滑鼠移動可能更難,但有時非常有用。如果你真的想移動滑鼠,請改用 Input.set_mouse_position(<Vector2>)。這也會生成一個 InputEventMouseMotion 事件以觸發。

變數
變數 用途
position 新的滑鼠位置,相對於節點的視口。如果在 _gui_input 中呼叫,它相對於 Control 節點。
relative 相對於上次呼叫中的滑鼠位置的新位置。
speed 滑鼠速度,以畫素/秒為單位

預設情況下,此事件最多每渲染一幀只發出一次。如果你需要更精確的輸入報告,請考慮使用 Input.set_use_accumulated_input(false) 以儘可能頻繁地發出事件。如果你需要這樣做來繪製徒手線條,請考慮使用 Bresenham's 線演算法 以及避免在快速移動滑鼠時出現間隙。

InputEventScreenDrag

[編輯 | 編輯原始碼]

(僅在移動裝置上可用)

讀取和寫入螢幕拖動比 InputEventMouseMotion 更難,僅僅因為你無法透過程式碼強制使用者移動他們的手指。好吧,這是謊言。但是要做到這一點,你需要有心靈控制或催眠方面的學位,這遠遠超出了本書的範圍!

變數
變數 用途
position 手指相對於節點視口的新位置。如果在 _gui_input 中使用,它相對於 Control 節點。
relative 手指的新位置,相對於其舊位置。
speed 拖動速度,以畫素/秒為單位。

InputEventScreenTouch

[編輯 | 編輯原始碼]

(僅在移動裝置上可用)

此事件用於輕觸(或取消輕觸)螢幕。

變數
變數 用途
position 手指相對於節點視口的位置。如果在 _gui_input 中使用,它相對於 Control。
pressed 如果為 true,則使用者正在將手指放在螢幕上。否則,他們正在將手指從螢幕上拿開。

InputEventJoypadButton

[編輯 | 編輯原始碼]

此 InputEvent 用於檢測手柄按鈕(即:連線到計算機或控制檯的控制器上的按鈕)。

變數
變數 關於
button_index 按下的按鈕。
如果為“true”,則按鈕被按下。否則按鈕被釋放。

InputEventJoypadMotion

[編輯 | 編輯原始碼]

此事件用於一次移動一個軸的搖桿。此 InputEvent 可能令人困惑。

變數
變數 關於
一個常量,具有六個值之一:JOY_AXIS_*,其中 "*" 可以是

0:水平軸上的左搖桿

1:垂直軸上的左搖桿

2:水平軸上的右搖桿

3:垂直軸上的右搖桿

6:左扳機模擬軸

7:右扳機模擬軸

其他四個目前沒有功能,被描述為“通用遊戲手柄軸”,只是用作空白。

軸值 從 -1.0 到 1.0 的數字。

重要的是要知道,此 InputEvent 沒有可以讀取的 Vector2 值。以下指令碼將此 InputEvent 轉換為 Vector3,x 和 y 用於位置,z 用於移動的搖桿。

func convert_from_joypad_motion(event: InputEventJoypadMotion) -> Vector3:
  match event.axis:
    JOY_AXIS_0:# Left stick horizontal
      return Vector3(event.axis_value, 0, 0)
    JOY_AXIS_1:# Left stich vertical
      return Vector3(0, event.axis_value, 0)
    JOY_AXIS_2:# Right stick horizontal
      return Vector3(event.axis_value, 0, 1)
    JOY_AXIS_3:# Right stick vertical
      return Vector3(0, event.axis_value, 1)
  # An error occurred
  printerr("Invalid axis: %s in call to convert_from_joypad_motion" % [event.axis])
  print_stack() # To help with debugging, print the call stack.
  return Vector3(0, 0, 0)



Godot 遊戲引擎指南

入門 [編輯]
安裝
什麼是節點?
程式設計
資源和匯入
訊號和方法
你的第一個遊戲
使它工作
除錯
輸入
物理
儲存和載入
多人遊戲
讓它看起來不錯
UI 皮膚
動畫
高階幫助
伺服器(單例)
平臺特定
最佳化
加密
匯出
外掛
其他
有用連結
作者和貢獻者
列印版本


<-- 上一個 返回頂部 下一個 -->

華夏公益教科書