跳转至内容

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 皮肤
动画
高级帮助
服务器(单例)
平台特定
优化
加密
导出
插件
其他
有用链接
作者和贡献者
打印版本


<-- 上一个 返回顶部 下一个 -->

华夏公益教科书