InputEvent¶
这是怎么一回事?¶
管理输入通常很复杂,无论是操作系统还是平台。为了减轻这一点,提供了一种特殊的内置类型, InputEvent . 可以将此数据类型配置为包含多种类型的输入事件。输入事件通过引擎传输,根据用途,可以在多个位置接收。
下面是一个快速的例子,如果按下Escape键,游戏将结束:
func _unhandled_input(event):
if event is InputEventKey:
if event.pressed and event.scancode == KEY_ESCAPE:
get_tree().quit()
public override void _UnhandledInput(InputEvent @event)
{
if (@event is InputEventKey eventKey)
if (eventKey.Pressed && eventKey.Scancode == (int)KeyList.Escape)
GetTree().Quit();
}
但是,使用所提供的 InputMap 功能,允许您定义输入操作并分配不同的键。通过这种方式,您可以为同一个操作定义多个键(例如,它们键盘上的Escape键和游戏板上的Start按钮)。然后,您可以更容易地在项目设置中更改此映射,而无需更新代码,甚至在其上构建一个键映射功能,以允许您的游戏在运行时更改键映射!
您可以在下面设置输入地图 Project > Project Settings > Input Map 然后这样做:
func _process(delta):
if Input.is_action_pressed("ui_right"):
# Move right
public override void _Process(float delta)
{
if (Input.IsActionPressed("ui_right"))
{
// Move right
}
}
它是如何工作的?¶
每个输入事件都源于用户/播放器(尽管可以生成一个输入事件并将其反馈给引擎,这对于手势很有用)。每个平台的OS对象将从设备中读取事件,然后将它们馈送给mainloop。AS SceneTree 是默认的mainloop实现,事件被发送到它。godot提供了一个函数来获取当前scenetree对象: get_tree() .
但是scenetree不知道如何处理该事件,因此它将从“根”开始将其提供给视区。 Viewport (场景树的第一个节点)。viewport对接收到的输入进行了大量的处理,顺序如下:
首先,标准 Node._input() 函数将在覆盖它的任何节点中被调用(并且没有用 Node.set_process_input() )如果任何函数使用事件,它可以调用 SceneTree.set_input_as_handled() 事件不会再蔓延。这确保您可以过滤所有感兴趣的事件,甚至在GUI之前。对于游戏输入, Node._unhandled_input() 通常更适合,因为它允许GUI拦截事件。
第二,它将尝试将输入馈送到GUI,并查看是否有任何控件可以接收它。如果是这样的话, Control 将通过虚拟函数调用 Control._gui_input() 并发出信号“input_event”(此函数可通过继承脚本重新实现)。如果控件想要“使用”事件,它将调用 Control.accept_event() 这件事不会再扩散了。使用 Control.mouse_filter 属性来控制 Control 通过以下方式通知鼠标事件: Control._gui_input() 回调,以及是否进一步传播这些事件。
如果到目前为止没有人使用该事件,则在重写(而不是用禁用)时将调用未处理的输入回调 Node.set_process_unhandled_input() )如果任何函数使用事件,它可以调用 SceneTree.set_input_as_handled() 事件不会再蔓延。未经处理的输入回调非常适合全屏幕游戏事件,因此当GUI处于活动状态时不会接收到它们。
如果到目前为止没有人想参加这个活动, Camera 指定给视区后,将投射到物理世界的光线(单击后的光线方向)。如果此光线击中对象,它将调用 CollisionObject._input_event() 相关物理对象中的函数(默认情况下,实体接收此回调,但区域不接收)。可以通过以下方式配置 Area 属性)。
最后,如果事件未经处理,它将传递到树中的下一个视区,否则将被忽略。
将事件发送到场景中的所有侦听节点时,视区将按第一个相反的深度顺序执行:从场景树底部的节点开始,到根节点结束:
GUI事件也会在场景树上传播,但由于这些事件针对特定的控件,因此只有目标控制节点的直接祖先才能接收事件。
根据Godot的基于节点的设计,这使得专门的子节点能够处理和使用特定的事件,而它们的祖先,以及最终的场景根,可以在需要时提供更广泛的行为。
子宫内口解剖¶
InputEvent 只是一个基本的内置类型,它不代表任何内容,只包含一些基本信息,例如事件ID(每个事件都会增加)、设备索引等。
有几种专门类型的住院病患,如下表所述:
事件 |
类型索引 |
描述 |
NONE |
空输入事件。 |
|
KEY |
包含scancode和unicode值以及修饰符。 |
|
MOUSE_BUTTON |
包含单击信息,如按钮、修改器等。 |
|
MOUSE_MOTION |
包含运动信息,如相对位置、绝对位置和速度。 |
|
JOYSTICK_MOTION |
包含操纵杆/操纵手柄模拟轴信息。 |
|
JOYSTICK_BUTTON |
包含操纵杆/操纵手柄按钮信息。 |
|
SCREEN_TOUCH |
包含多点触控新闻/发布信息。(仅在移动设备上可用) |
|
SCREEN_DRAG |
包含多点触控拖动信息。(仅在移动设备上可用) |
|
SCREEN_ACTION |
包含一般操作。这些事件通常由程序员作为反馈生成。(更多内容见下文) |
行动¶
输入事件可能代表或不代表预先定义的操作。动作很有用,因为它们在编程游戏逻辑时抽象输入设备。这允许:
在不同的设备上使用相同的代码,具有不同的输入(例如,PC上的键盘、控制台上的游戏板)。
要在运行时重新配置的输入。
可以从“操作”选项卡中的“项目设置”菜单创建操作。
任何事件都有方法 InputEvent.is_action() , InputEvent.is_pressed() 和 InputEvent .
或者,可能需要向游戏提供来自游戏代码的操作(这方面的一个很好的例子是检测手势)。输入单例有一个方法: Input.parse_input_event() . 您通常会这样使用它:
var ev = InputEventAction.new()
# set as move_left, pressed
ev.action = "move_left"
ev.pressed = true
# feedback
Input.parse_input_event(ev)
var ev = new InputEventAction();
// set as move_left, pressed
ev.SetAction("move_left");
ev.SetPressed(true);
// feedback
Input.ParseInputEvent(ev);