Up to date

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

Utilisation d'InputEvent

Qu'est-ce que c'est ?

La gestion des entrées est généralement complexe, quel que soit le système d'exploitation ou la plate-forme. Pour faciliter un peu les choses, un type spécial intégré est fourni, InputEvent. Ce type de données peut être configuré pour contenir plusieurs types d'événements d'entrée. Les événements d'entrée voyagent à travers le moteur et peuvent être reçus à plusieurs endroits, selon le but recherché.

Voici un exemple rapide, la fermeture de votre jeu si la touche quitter est appuyée :

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

Cependant, il est plus propre et plus flexible d'utiliser la fonction fournie InputMap, qui vous permet de définir des actions d'entrée et de leur assigner différentes touches. De cette façon, vous pouvez définir plusieurs touches pour la même action (par exemple, la touche d'Échaptr et le bouton start sur une manette de jeu). Vous pouvez alors plus facilement changer cette cartographie dans les paramètres du projet sans mettre à jour votre code, et même construire une fonction de cartographie de touche par-dessus pour permettre à votre jeu de changer la cartographie de touche pendant l'exécution !

Vous pouvez configurer votre InputMap sous Project > Project Settings > Input Map et utiliser ces actions comme ceci :

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

Comment ça marche ?

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().

When sending events to its child and descendant nodes, the viewport will do so, as depicted in the following graphic, in a reverse depth-first order, starting with the node at the bottom of the scene tree, and ending at the root node. Excluded from this process are Windows and SubViewports.

../../_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.

Les événements de l'interface graphique remontent également dans l'arbre des scènes mais, comme ces événements ciblent des Controls spécifiques, seuls les ancêtres directs du nœud de Control ciblé reçoivent l'événement.

Conformément au design de Godot basée sur les nœuds, cela permet à des nœuds enfants spécialisés de gérer et de consommer des événements particuliers, tandis que leurs ancêtres, et finalement la racine de la scène, peuvent fournir un comportement plus généralisé si nécessaire.

Anatomie d'un InputEvent

InputEvent est juste un type intégré de base, il ne représente rien et contient seulement quelques informations de base, comme l'ID de l'événement (qui est incrémenté pour chaque événement), l'index du périphérique, etc.

Il existe plusieurs types spécialisés d'InputEvent, décrits dans le tableau ci-dessous :

Évènement

Description

InputEvent

Évènement d'entrée vide.

InputEventKey

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

InputEventMouseButton

Contient des informations de clic, telles que bouton, modificateurs, etc.

InputEventMouseMotion

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

InputEventJoypadMotion

Contient l'information de l(axe analogique du Joystick/Joypad.

InputEventJoypadButton

Contient des informations sur les boutons de la manette/du joystick.

InputEventScreenTouch

Contient des informations de pression/relâchement multi-touche. (uniquement disponible sur les appareils mobiles)

InputEventScreenDrag

Contient des informations de glissement multi-touche. (uniquement disponible sur les appareils mobiles)

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

Contient une action générique. Ces événements sont souvent générés par le programmeur en tant que retour d'information. (plus d'informations ci-dessous)

Actions

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:

  • Le même code pour travailler sur différents appareils avec différentes entrées (par exemple, clavier sur PC, Joypad sur console).

  • Entrée à reconfigurer au moment de l'exécution.

  • 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.

Tout événement a les méthodes InputEvent.is_action(), InputEvent.is_pressed() et InputEvent.

Alternativement, il peut être souhaité de fournir au jeu un retour avec une action à partir du code de jeu (un bon exemple de cela est la détection des gestes). Le singleton Input a une méthode pour cela : Input.parse_input_event(). Vous l'utiliseriez normalement comme ceci :

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

InputMap

Il est souvent souhaitable de personnaliser et de re-cartographier les entrées à partir du code. Si tout votre workflow dépend d'actions, le singleton InputMap est idéal pour réaffecter ou créer différentes actions à l'exécution. Ce singleton n'est pas sauvegardé (doit être modifié manuellement) et son état est lancé à partir des paramètres du projet (project.godot). Ainsi, tout système dynamique de ce type doit stocker les paramètres de la manière la plus appropriée pour le programmeur.