问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Godot 游戏引擎 v4.3 输入事件处理教程

创作时间:
作者:
@小白创作中心

Godot 游戏引擎 v4.3 输入事件处理教程

引用
1
来源
1.
https://www.bookstack.cn/read/godot-4.3-zh/4fcb7b00aa7523c9.md

在游戏开发中,处理玩家输入是至关重要的环节。Godot游戏引擎提供了强大的输入事件系统,支持键盘、鼠标、手柄等多种输入设备。本文将详细介绍如何在Godot 4.3版本中处理各种输入事件,包括事件轮询、输入映射、键盘事件、鼠标事件和触摸事件等。

事件和轮询

在处理玩家输入时,有两种主要方式:事件驱动和状态轮询。

  • 事件驱动:使用_input()函数来响应特定的输入事件,如按键按下。
  • 状态轮询:通过Input单例查询某个输入的状态,适用于需要持续检测的场景,如移动。

示例代码展示了如何在GDScript和C#中实现这两种方式:

func _input(event):
    if event.is_action_pressed("jump"):
        jump()

func _physics_process(delta):
    if Input.is_action_pressed("move_right"):
        position.x += speed * delta
public override void _Input(InputEvent @event)
{
    if (@event.IsActionPressed("jump"))
    {
        Jump();
    }
}

public override void _PhysicsProcess(double delta)
{
    if (Input.IsActionPressed("move_right"))
    {
        position.X += speed * (float)delta;
    }
}

输入事件

输入事件是继承自InputEvent的对象,根据事件类型不同,对象会包含相关的属性。例如,按键事件会包含按键代码,鼠标事件会包含位置信息。

为了更好地理解输入事件,可以添加一个节点并附加以下脚本:

extends Node

func _input(event):
    print(event.as_text())
using Godot;

public partial class Node : Godot.Node
{
    public override void _Input(InputEvent @event)
    {
        GD.Print(@event.AsText());
    }
}

运行后,你可以在输出窗口中看到每个输入事件的详细信息。

InputMap

InputMap是处理各种输入的最灵活方式。你可以创建命名的输入动作,并将多个输入事件(如按键或鼠标点击)映射到同一个动作上。在项目设置中可以查看和添加自定义的输入动作。

一旦定义了动作,就可以在脚本中使用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 @event)
{
    if (@event.IsActionPressed("my_action"))
    {
        GD.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")
public override void _Input(InputEvent @event)
{
    if (@event is InputEventKey keyEvent && keyEvent.Pressed)
    {
        if (keyEvent.Keycode == Key.T)
        {
            GD.Print("T was pressed");
        }
    }
}

键盘修饰键

修饰键属性继承自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")
public override void _Input(InputEvent @event)
{
    if (@event is InputEventKey keyEvent && keyEvent.Pressed)
    {
        switch (keyEvent.Keycode)
        {
            case Key.T:
                GD.Print(keyEvent.ShiftPressed ? "Shift+T was pressed" : "T was pressed");
                break;
        }
    }
}

鼠标事件

鼠标事件继承自InputEventMouse,并被分为InputEventMouseButtonInputEventMouseMotion两种类型。所有鼠标事件都包含position属性。

鼠标按钮

捕获鼠标按钮与处理按键事件类似。@GlobalScope_MouseButton包含了一系列鼠标按钮常量,如MOUSE_BUTTON_LEFTMOUSE_BUTTON_WHEEL_UP

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")
public override void _Input(InputEvent @event)
{
    if (@event is InputEventMouseButton mouseEvent && mouseEvent.Pressed)
    {
        switch (mouseEvent.ButtonIndex)
        {
            case MouseButton.Left:
                GD.Print($"Left button was clicked at {mouseEvent.Position}");
                break;
            case MouseButton.WheelUp:
                GD.Print("Wheel up");
                break;
        }
    }
}

鼠标行为

InputEventMouseMotion在鼠标移动时触发,可以通过relative属性获取移动的距离。下面是一个使用鼠标事件实现拖拽的示例:

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
using Godot;

public partial class MyNode2D : Node2D
{
    private bool _dragging = false;
    private int _clickRadius = 32; // Size of the sprite.

    public override void _Input(InputEvent @event)
    {
        Sprite2D sprite = GetNodeOrNull<Sprite2D>("Sprite2D");
        if (sprite == null)
        {
            return; // No suitable node was found.
        }

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

触摸事件

如果你使用的是触摸屏设备,就可以生成触摸事件。InputEventScreenTouch相当于鼠标点击事件,而InputEventScreenDrag的工作原理与鼠标移动一致。

在非触摸屏设备上测试触摸事件,可以在项目设置中启用“Emulate Touch From Mouse”选项。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号