Godot 遊戲引擎指南/輸入
在每個遊戲中,你都可以按下按鈕或點選螢幕來執行操作。這被稱為對輸入做出反應。有兩種方法可以做到:使用輸入對映和手動方式。
轉到你的專案設定,在專案 -> 專案設定... 中點選輸入對映選項卡。你會看到一個輸入動作列表,例如 "ui_select"。這些是預設的動作,可以編輯,但不能刪除。
但是,你可以 - 也應該 - 建立你自己的輸入動作。在顯示 "動作:" 的地方,輸入一個動作名稱,例如 "射擊" 或 "前進"。按下它旁邊的 "新增" 按鈕。這將建立你的動作。
你會注意到它沒有關聯的輸入事件。按下你新建動作旁邊的 "+" 按鈕。你會看到以下選項:
- 鍵:允許你連結任何鍵盤按鈕。
- 搖桿按鈕:允許你連結手柄按鈕。
- 搖桿軸:允許你連結手柄搖桿運動。
- 滑鼠按鈕:允許你連結滑鼠按鈕。
對於觸控式螢幕和滑鼠移動,請參閱下面提到的手動輸入檢測部分。
有幾種方法可以檢測它們是否被按下,你選擇的方法取決於動作的用途。下面的函式返回一個布林值,除非另有說明,否則應放在 "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 教程.
因此,讀取輸入非常有趣。但是,還有幾種更常用的輸入方法。在你繼續閱讀之前,嘗試思考一下它們是什麼?
除了使用輸入單例之外,還有更多方法,本節將深入解釋可以實現的功能以及如何實現。
動作控制存在於許多流行遊戲中,特別是 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 的詳細介紹,請參見此處.
以下程式碼建立了一個射擊動作,它對應於按下空格鍵。
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 的更多資訊,請參見下面的 "偽造" 輸入部分。
其他有用方法
- load_from_globals(): 將動作重置為專案設定中設定的動作。
- has_action(action: String): 如果動作存在,則返回 true。
- action_erase_events(action: String): 清除動作,使其不再有任何關聯事件。
- erase_action(action: String): 刪除動作。
與往常一樣,這並非列出所有方法。只是一些方法。
要錄製音訊,你需要執行兩項操作:
- 按下螢幕底部的 "音訊" 按鈕,然後按下 "新建匯流排"。將其重新命名為 "麥克風",然後點選 "新增效果"。在出現的下拉選單中按下 "錄製"。
- 為你的場景建立一個新的 AudioStreamPlayer 節點。在檢查器中點選流值。從出現的下拉選單中選擇新建 AudioStreamMicrophone。將 "匯流排" 屬性設定為 "麥克風"。每當你想在遊戲中錄製音訊時,只需將 "播放" 值設定為 true 即可。
讀取音訊以進行語音識別等操作可以實現,但並不容易,超出了本書(以及作者知識)的範圍。
所以,你決定要在執行時更改 InputMap?但是該怎麼做呢?
Godot 有幾個強大的類,它們使輸入檢測更容易,並且可以偽造輸入。
更多資訊請參見:InputEvent 教程.
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 | 媒體播放 鍵 |
如果你想檢測某些修飾符是否也被按下,你可以訪問這些變數
- alt: 如果必須按下鍵盤上的“Alt”,則設定為 true。
- ctrl: 如果必須按下鍵盤上的“Ctrl”(僅限 Windows),則設定為 true。
- meta: 如果必須按下鍵盤上的“Meta”(僅限 Linux),則設定為 true。
- command: 如果必須按下鍵盤上的“Ctrl”(在 Windows 上)或“Meta”(在 Linux 上),則設定為 true。
- shift: 如果必須按下鍵盤上的“shift”,則設定為 true。
你可以將其中多個設定為 true。這將使你需要按下所有設定的修飾符。
如果你想檢測釋放鍵而不是按下鍵,不要將“pressed”設定為 true。如果將其新增到 InputMap,它將在其鍵未按下時始終保持按下狀態,但只有在它們第一次釋放後才會發生。那麼如何解決這個問題呢?實際上,這很簡單!
試試 Input.event_<press/release>("shoot")。它工作得很好,但是如果你需要在 _input 的呼叫中使用它,你應該改用 Input.parse_input_event(event)。
檢測滑鼠輸入或模擬滑鼠輸入可以用兩種方式解釋:滑鼠按鈕和滑鼠移動。
另請參閱:滑鼠和輸入座標教程.
點選滑鼠是一個常見的操作,但模擬它並不常見。它是最簡單的閱讀和模擬的操作,只需要 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_LEFT | 左鍵單擊 |
| BUTTON_RIGHT | 右鍵單擊 |
| BUTTON_MIDDLE | 滾動按鈕按下 |
| BUTTON_WHEEL_UP | 向上滾動滾輪。 |
| BUTTON_WHEEL_DOWN | 向下滾動滾輪。 |
模擬滑鼠移動可能更難,但有時非常有用。如果你真的想移動滑鼠,請改用 Input.set_mouse_position(<Vector2>)。這也會生成一個 InputEventMouseMotion 事件以觸發。
| 變數 | 用途 |
|---|---|
| position | 新的滑鼠位置,相對於節點的視口。如果在 _gui_input 中呼叫,它相對於 Control 節點。 |
| relative | 相對於上次呼叫中的滑鼠位置的新位置。 |
| speed | 滑鼠速度,以畫素/秒為單位 |
預設情況下,此事件最多每渲染一幀只發出一次。如果你需要更精確的輸入報告,請考慮使用 Input.set_use_accumulated_input(false) 以儘可能頻繁地發出事件。如果你需要這樣做來繪製徒手線條,請考慮使用 Bresenham's 線演算法 以及避免在快速移動滑鼠時出現間隙。
(僅在移動裝置上可用)
讀取和寫入螢幕拖動比 InputEventMouseMotion 更難,僅僅因為你無法透過程式碼強制使用者移動他們的手指。好吧,這是謊言。但是要做到這一點,你需要有心靈控制或催眠方面的學位,這遠遠超出了本書的範圍!
| 變數 | 用途 |
|---|---|
| position | 手指相對於節點視口的新位置。如果在 _gui_input 中使用,它相對於 Control 節點。 |
| relative | 手指的新位置,相對於其舊位置。 |
| speed | 拖動速度,以畫素/秒為單位。 |
(僅在移動裝置上可用)
此事件用於輕觸(或取消輕觸)螢幕。
| 變數 | 用途 |
|---|---|
| position | 手指相對於節點視口的位置。如果在 _gui_input 中使用,它相對於 Control。 |
| pressed | 如果為 true,則使用者正在將手指放在螢幕上。否則,他們正在將手指從螢幕上拿開。 |
此 InputEvent 用於檢測手柄按鈕(即:連線到計算機或控制檯的控制器上的按鈕)。
| 變數 | 關於 |
|---|---|
| button_index | 按下的按鈕。 |
| 如果為“true”,則按鈕被按下。否則按鈕被釋放。 |
此事件用於一次移動一個軸的搖桿。此 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)
