Input examples

简介

在本教程中,您将学习如何使用Godot的:ref:`输入事件<class_InputEvent>`系统捕获玩家输入。您的游戏可以使用多种不同类型的输入——键盘,游戏手柄,鼠标等等。还有许多不同的方法,将这些输入转化为游戏中的动作。本文将向您展示一些最常见的场景,您可以将其作为您自己项目的起点。

注解

要详细了解Godot的输入事件系统是如何工作的,请见:ref:文档_输入事件

事件和轮询

有时候,你想让游戏对某个输入事件做出反应——例如按下“跳跃”按钮。对于其他情况,可能希望只要按下键就会发生一些事情,比如移动。在第一种情况下,您可以使用“_input()”函数,它将在发生输入事件时调用。在第二种情况下,Godot提供了:ref:`输入<class_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
public override void _Input(InputEvent inputEvent)
{
    if (inputEvent.IsActionPressed("jump"))
    {
        Jump();
    }
}

public override void _PhysicsProcess(float delta)
{
    if (Input.IsActionPressed("move_right"))
    {
        // Move as long as the key/button is pressed.
        position.x += speed * delta;
    }
}

这使您能够灵活地混合和匹配所执行输入的处理类型。

对于本教程的其余部分,我们将专注于使用“_input ()”捕捉单个事件。

输入事件

输入事件是继承自:ref:`输入事件<class_InputEvent>`的对象。根据事件类型,对象将包含与该事件相关的特定属性。为了了解事件的实际情况,添加一个节点并附加以下脚本:

extends Node

func _input(event):
    print(event.as_text())
public override void _Input(InputEvent inputEvent)
{
    GD.Print(inputEvent.AsText());
}

当你按下按键,移动鼠标,并执行其他输入,您会在输出窗口中看到每个事件滚动。下面是输出的一个例子:

A
InputEventMouseMotion : button_mask=0, position=(551, 338), relative=(-85, 47), speed=(0, 0)
InputEventMouseButton : button_index=BUTTON_LEFT, pressed=true, position=(551, 338), button_mask=1, doubleclick=false
InputEventMouseButton : button_index=BUTTON_LEFT, pressed=false, position=(551, 338), button_mask=0, doubleclick=false
S
F
InputEventMouseMotion : button_mask=0, position=(547, 338), relative=(-1, 0), speed=(0, 0)
InputEventMouseMotion : button_mask=0, position=(542, 338), relative=(-4, 0), speed=(0, 0)

如你所见,对于不同类型的输入,结果是非常不同的。按键事件甚至被打印为按键符号。例如,让我们考虑:ref:鼠标按钮输入事件<class_InputEventMouseButton>。它继承自以下类:

  • InputEvent - the base class for all input events
  • InputEventWithModifiers - adds the ability to check if modifiers are pressed, such as Shift or Alt.
  • InputEventMouse - adds mouse event properties, such as position
  • :ref:`鼠标按钮输入事件<class_InputEventMouseButton>`包含按下的按钮的索引,无论是双击,或是其他。

小技巧

在处理事件时,打开类引用是一个好主意,这样可以检查事件类型的可用属性和方法。

You can encounter errors if you try to access a property on an input type that doesn't contain it - calling position on InputEventKey for example. To avoid this, make sure to test the event type first:

func _input(event):
    if event is InputEventMouseButton:
        print("mouse button event at ", event.position)
public override void _Input(InputEvent inputEvent)
{
    if (inputEvent is InputEventMouseButton mouseEvent)
    {
        GD.Print($"mouse button event at {mouseEvent.Position}");
    }
}

InputMap

:ref:`事件表<class_InputMap>`是处理各种输入的最灵活的方法。您可以通过创建命名的输入*动作*来使用它,可以为它分配任意数量的输入事件,例如按键或鼠标点击。一个新的Godot项目已经包含许多默认定义操作。看看它们,然后添加你自己的,打开项目->项目设置,并选择事件表选项卡:

../../_images/inputs_inputmap.png

Capturing actions

一旦你定义了动作,可以在脚本中使用“is_action_pressed()”和“is_action_released ()”处理它们。通过名称查找响应的动作:

func _input(event):
    if event.is_action_pressed("my_action"):
        print("my_action occurred!")
public override void _Input(InputEvent inputEvent)
{
    if (inputEvent.IsActionPressed("my_action"))
    {
        GD.Print("my_action occurred!");
    }
}

键盘事件

Keyboard events are captured in InputEventKey. While it's recommended to use input actions instead, there may be cases where you want to specifically look at key events. For this example, let's check for the T:

func _input(event):
    if event is InputEventKey and event.pressed:
        if event.scancode == KEY_T:
            print("T was pressed")
public override void _Input(InputEvent inputEvent)
{
    if (inputEvent is InputEventKey keyEvent && keyEvent.Pressed)
    {
        if ((KeyList)keyEvent.Scancode == KeyList.T)
        {
            GD.Print("T was pressed");
        }
    }
}

小技巧

详见:参考:“@全局范围_键位列表<枚举_@全局范围_键位列表>”获取扫描代码常量列表。

键盘修饰符

Modifier properties are inherited from InputEventWithModifiers. This allows you to check for modifier combinations using boolean properties. Let's imagine you want one thing to happen when the T is pressed, but something different when it's Shift + T:

func _input(event):
    if event is InputEventKey and event.pressed:
        if event.scancode == KEY_T:
            if event.shift:
                print("Shift+T was pressed")
            else:
                print("T was pressed")
public override void _Input(InputEvent inputEvent)
{
    if (inputEvent is InputEventKey keyEvent && keyEvent.Pressed)
    {
        switch ((KeyList)keyEvent.Scancode)
        {
            case KeyList.T:
                GD.Print(keyEvent.Shift ? "Shift+T was pressed" : "T was pressed");
                break;
        }
    }
}

小技巧

详见:参考:“@全局范围_键位列表<枚举_@全局范围_键位列表>”获取扫描代码常量列表。

鼠标事件

鼠标事件继承自:参考:'鼠标输入事件<类_鼠标输入事件>'类,并被分成两种类型::参考:'鼠标按钮输入事件<类_鼠标按钮输入事件>'和:参考:“鼠标行为输入事件<类_鼠标行为输入事件>”。注意,这意味着所有鼠标事件将包含一个“位置”(position)属性。

鼠标按钮

捕获鼠标按钮与处理按键事件非常相似。@全局作用域_按钮列表 包含每个可能按钮的“按钮_*”常量列表,它将在事件的“按钮_索引”属性中报告。注意,鼠标滚轮也可以算作一个按钮——准确地说,是两个按钮,“按钮_滚轮_上”和“按钮_滚轮_下”都是独立的事件。

func _input(event):
    if event is InputEventMouseButton:
        if event.button_index == BUTTON_LEFT and event.pressed:
            print("Left button was clicked at ", event.position)
        if event.button_index == BUTTON_WHEEL_UP and event.pressed:
            print("Wheel up")
public override void _Input(InputEvent inputEvent)
{
    if (inputEvent as InputEventMouseButton mouseEvent && mouseEvent.Pressed)
    {
        switch ((ButtonList)mouseEvent.ButtonIndex)
        {
            case ButtonList.Left:
                GD.Print($"Left button was clicked at {mouseEvent.Position}");
                break;
            case ButtonList.WheelUp:
                GD.Print("Wheel up");
                break;
        }
    }
}

鼠标行为

:ref:`鼠标移动输入事件<class_InputEventMouseMotion>`事件在鼠标移动时发生。可以通过“相对”属性找到移动的距离。

下面是一个使用鼠标事件拖放:ref:`精灵<class_Sprite>`节点的例子:

extends Node

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

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

    if event is InputEventMouseMotion and dragging:
        # While dragging, move the sprite with the mouse.
        $Sprite.position = event.position
public override void _Input(InputEvent inputEvent)
{
    var sprite = GetNodeOrNull<Sprite>("Sprite");
    if (sprite == null)
        return;// No suitable node was found.

    if (inputEvent is InputEventMouseButton mouseEvent && (ButtonList)mouseEvent.ButtonIndex == ButtonList.Left)
    {
        if ((mouseEvent.Position - sprite.Position).Length() < clickRadius)
        {
            // Start dragging if the click is on the sprite.
            if (!dragging && mouseEvent.Pressed)
                dragging = !dragging;
        }
        // Stop dragging if the button is released.
        if (dragging && !mouseEvent.Pressed)
        {
            dragging = false;
        }
    }
    else
    {
        if (inputEvent is InputEventMouseMotion motionEvent)
        {
            // While dragging, move the sprite with the mouse.
            sprite.Position = motionEvent.Position;
        }
    }
}

Touch events

如果使用触摸屏设备,可以生成触摸事件。:ref:`触摸屏幕输入事件<class_InputEventScreenTouch>`相当于鼠标点击事件,并且:ref:`拖拽屏幕输入事件<class_InputEventScreenDrag>`的工作原理与鼠标移动非常相似。

小技巧

要在非触摸屏设备上测试触摸事件,打开项目设置,进入“输入设备/指向”部分。启用“模拟鼠标触摸”,您的项目将把鼠标单击和移动解释为触摸事件。