Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Використання inputEvent

Що це таке?

Управління входом, як правило, складне, незалежно від ОС, або платформи. Щоб трохи полегшити це, передбачений спеціальний вбудований тип Вхідних Подій InputEvent. Цей тип даних можна настроїти так, щоб він містив кілька типів вхідних подій. Вхідні події проходять через рушій і можуть бути отримані в декількох місцях, в залежності від мети.

Ось короткий приклад, закривання гри при натисканні клавіші Esc:

func _unhandled_input(event):
    if event is InputEventKey:
        if event.pressed and event.keycode == KEY_ESCAPE:
            get_tree().quit()

Однак чистіше і зручніше використовувати надану функцію Карти Введення InputMap, яка дозволяє визначати дії введення і призначати їм різні клавіші. Таким чином, ви можете визначити кілька клавіш для однієї дії (наприклад, клавішу виходу з клавіатури та кнопку пуску на геймпаді). Потім ви зможете легше змінити ці призначення в параметрах проекту, не оновлюючи код, і навіть створити функцію перепризначення клавіш, щоб дозволити гравцям призначати зручні для них клавіші!

Карту вводу можна настроїти в розділі Проект > Параметри проекту > Input Map, а потім використати ці дії, наприклад, так:

func _process(delta):
    if Input.is_action_pressed("ui_right"):
        # Move right.

Як усе це працює?

Every input event is originated from the user/player (though it's possible to generate an InputEvent and feed them back to the engine, which is useful for gestures). The DisplayServer for each platform will read events from the operating system, then feed them to the root Window.

The window's Viewport does quite a lot of stuff with the received input, in order:

../../_images/input_event_flow.webp
  1. If the Viewport is embedding Windows, the Viewport tries to interpret the event in its capability as a Window-Manager (e.g. for resizing or moving Windows).

  2. Next if an embedded Window is focused, the event is sent to that Window and processed in the Windows Viewport and afterwards treated as handled. If no embedded Window is focused, the event is sent to the nodes of the current viewport in the following order.

  3. First of all, the standard Node._input() function will be called in any node that overrides it (and hasn't disabled input processing with Node.set_process_input()). If any function consumes the event, it can call Viewport.set_input_as_handled(), and the event will not spread any more. This ensures that you can filter all events of interest, even before the GUI. For gameplay input, Node._unhandled_input() is generally a better fit, because it allows the GUI to intercept the events.

  4. Second, it will try to feed the input to the GUI, and see if any control can receive it. If so, the Control will be called via the virtual function Control._gui_input() and the signal "gui_input" will be emitted (this function is re-implementable by script by inheriting from it). If the control wants to "consume" the event, it will call Control.accept_event() and the event will not spread any more. Use the Control.mouse_filter property to control whether a Control is notified of mouse events via Control._gui_input() callback, and whether these events are propagated further.

  5. If so far no one consumed the event, the Node._shortcut_input() callback will be called if overridden (and not disabled with Node.set_process_shortcut_input()). This happens only for InputEventKey, InputEventShortcut and InputEventJoypadButton. If any function consumes the event, it can call Viewport.set_input_as_handled(), and the event will not spread any more. The shortcut input callback is ideal for treating events that are intended as shortcuts.

  6. If so far no one consumed the event, the Node._unhandled_key_input() callback will be called if overridden (and not disabled with Node.set_process_unhandled_key_input()). This happens only if the event is a InputEventKey. If any function consumes the event, it can call Viewport.set_input_as_handled(), and the event will not spread any more. The unhandled key input callback is ideal for key events.

  7. If so far no one consumed the event, the Node._unhandled_input() callback will be called if overridden (and not disabled with Node.set_process_unhandled_input()). If any function consumes the event, it can call Viewport.set_input_as_handled(), and the event will not spread any more. The unhandled input callback is ideal for full-screen gameplay events, so they are not received when a GUI is active.

  8. If no one wanted the event so far, and Object Picking is turned on, the event is used for object picking. For the root viewport, this can also be enabled in Project Settings. In the case of a 3D scene if a Camera3D is assigned to the Viewport, a ray to the physics world (in the ray direction from the click) will be cast. If this ray hits an object, it will call the CollisionObject3D._input_event() function in the relevant physics object (bodies receive this callback by default, but areas do not. This can be configured through Area3D properties). In the case of a 2D scene, conceptually the same happens with CollisionObject2D._input_event().

При надсиланні подій до своїх дочірніх та нащадкових вузлів, видошукач буде робити це, як показано на наступному рисунку, у зворотному порядку від глибини до початку, починаючи з вузла у нижній частині дерева сцени, і закінчуючи кореневим вузлом. З цього процесу виключаються вікна та підвікна.

../../_images/input_event_scene_flow.png

This order doesn't apply to Control._gui_input(), which uses a different method based on event location or focused Control.

Since Viewports don't send events to other SubViewports, one of the following methods has to be used:

  1. Use a SubViewportContainer, which automatically sends events to its child SubViewports after Node._input() or Control._gui_input().

  2. Implement event propagation based on the individual requirements.

Події графічного інтерфейсу також переміщуються вгору по дереву сцени, але, оскільки ці події націлені на конкретні елементи керування (вузли Control), то події отримують лише прямі предки цільового вузла керування.

Відповідно до архітектури Godot, яка заснована на вузлах, це дозволяє спеціалізованим дочірнім вузлам обробляти і споживати певні події, в той час як їх предки, і в кінцевому підсумку корінь сцени, можуть забезпечити більш узагальнену поведінку, якщо це необхідно.

Анатомія InputEvent

InputEvent - це просто базовий вбудований тип вхідної події, він нічого не представляє і містить лише деяку основну інформацію, таку як ідентифікатор події (який збільшується для кожної події), індекс пристрою, тощо.

Існує кілька спеціалізованих типів InputEvent, описаних в таблиці нижче:

Подія

Опис

InputEvent

Порожня вхідна подія.

InputEventKey

Contains a keycode and Unicode value, as well as modifiers.

InputEventMouseButton

Містить інформацію про кліки мишкою, таку як клавіша, модифікатори тощо.

InputEventMouseMotion

Contains motion information, such as relative and absolute positions and speed.

InputEventJoypadMotion

Містить інформацію про аналогову вісь Джойстика/Джойпада.

InputEventJoypadButton

Містить інформацію про джойстик/джойпад.

InputEventScreenTouch

Містить інформацію про натискання/відтискання кількох дотиків. (доступно тільки на мобільних пристроях)

InputEventScreenDrag

Містить відомості про переміщення кількох дотиків. (доступно тільки на мобільних пристроях)

InputEventMagnifyGesture

Contains a position, a factor as well as modifiers.

InputEventPanGesture

Contains a position, a delta as well as modifiers.

InputEventMIDI

Contains MIDI-related information.

InputEventShortcut

Contains a shortcut.

InputEventAction

Містить загальну дію. Ці події часто генеруються програмістом як зворотний зв'язок. (Докладніше про це нижче)

Дії

Actions are a grouping of zero or more InputEvents into a commonly understood title (for example, the default "ui_left" action grouping both joypad-left input and a keyboard's left arrow key). They are not required to represent an InputEvent but are useful because they abstract various inputs when programming the game logic.

This allows for:

  • Один і той же код для роботи на різних пристроях з різними входами (наприклад, клавіатура на ПК, Joypad на консолі).

  • Переналаштування вводу під час виконання.

  • Actions to be triggered programmatically at run-time.

Actions can be created from the Project Settings menu in the Input Map tab and assigned input events.

Будь-яка подія має методи InputEvent.is_action(), InputEvent.is_pressed() та InputEvent.

Крім того, може знадобитися надати грі дію з коду гри (хорошим прикладом цього є виявлення жестів). Синглтон Input має для цього метод: Input.parse_input_event(). Зазвичай ви використовуєте його так:

var ev = InputEventAction.new()
# Set as ui_left, pressed.
ev.action = "ui_left"
ev.pressed = true
# Feedback.
Input.parse_input_event(ev)

InputMap (карта введення)

Часто потрібне налаштування та повторне зіставлення вхідних даних з коду. Якщо весь робочий процес залежить від дій, синглтон InputMap ідеально підходить для перепризначення, або створення, різних дій під час виконання. Цей синглтон не зберігається (потрібно змінювати вручну), а його стан запускається з параметрів проекту (project.godot). Таким чином, будь-яка динамічна система такого типу повинна зберігати налаштування так, як програміст найкраще вважає за потрібне.