输入示例

前言

在本教程中,你将学习如何使用 Godot 的 InputEvent 系统来捕获玩家输入。你的游戏可以使用多种不同类型的输入——键盘、游戏手柄、鼠标等——并且有多种不同的方法将这些输入转化为游戏中的动作。本文档将向你展示一些最常见的场景,你可以将其用作自己项目的起点。

备注

要详细了解 Godot 的输入事件系统是如何工作的,请参阅《使用 InputEvent》。

事件和轮询

有时你希望游戏响应某个输入事件——例如按下“跳跃”按钮。在其他情况下,你可能希望只要按下某个键就会发生某些事情,例如移动。在第一种情况下,你可以使用 _input() 函数,该函数将在输入事件发生时被调用。在第二种情况下,Godot 提供了 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 项目包含许多已定义的默认动作。要查看它们,请在“输入映射”对话框中打开 显示内置动作

捕捉动作

定义好动作后,你可以通过传递你要查找的动作的名称,使用 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 以获取键码常量列表。

警告

由于键盘冲突,如果你一次性按下了太多的键,那么在特定时间点,可能是无法将所有按键输入都进行注册的。根据按键在键盘上位置的不同,某些按键产生冲突的可能性会比其他的要高。有些键盘在硬件层面会提供抗冲突功能,不过在低端键盘和笔记本键盘上很少见。

因此,建议使用默认键盘布局,该布局被设计用于在没有抗冲突功能的键盘上正常工作。详情请参阅这个 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 的工作原理与鼠标移动一致。

小技巧

要在非触摸屏设备上测试触摸事件,请打开“项目设置”并转到“输入设备/指点”部分。启用“用鼠标模拟触摸”,你的项目将把鼠标点击和运动解释为触摸事件。