Merge pull request #6396 from Sauermann/fix-input-event-tutorial

Update Input Event Tutorial
This commit is contained in:
Max Hilbrunner
2023-01-09 23:03:44 +01:00
committed by GitHub
2 changed files with 48 additions and 17 deletions

View File

@@ -69,12 +69,17 @@ received input, in order:
.. image:: img/input_event_flow.png
1. First of all, the standard :ref:`Node._input() <class_Node_method__input>` function
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. 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 :ref:`Node._input() <class_Node_method__input>` function
will be called in any node that overrides it (and hasn't disabled input processing with :ref:`Node.set_process_input() <class_Node_method_set_process_input>`).
If any function consumes the event, it can call :ref:`Viewport.set_input_as_handled() <class_Viewport_method_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, :ref:`Node._unhandled_input() <class_Node_method__unhandled_input>` is generally a better fit, because it allows the GUI to intercept the events.
2. Second, it will try to feed the input to the GUI, and see if any
4. Second, it will try to feed the input to the GUI, and see if any
control can receive it. If so, the :ref:`Control <class_Control>` will be called via the
virtual function :ref:`Control._gui_input() <class_Control_method__gui_input>` and the signal
"gui_input" will be emitted (this function is re-implementable by
@@ -84,26 +89,52 @@ received input, in order:
property to control whether a :ref:`Control <class_Control>` is notified
of mouse events via :ref:`Control._gui_input() <class_Control_method__gui_input>`
callback, and whether these events are propagated further.
3. If so far no one consumed the event, the unhandled input callback
5. If so far no one consumed the event, the :ref:`Node._shortcut_input() <class_Node_method__shortcut_input>` callback
will be called if overridden (and not disabled with
:ref:`Node.set_process_shortcut_input() <class_Node_method_set_process_shortcut_input>`).
This happens only for :ref:`InputEventKey <class_InputEventKey>`,
:ref:`InputEventShortcut <class_InputEventShortcut>` and :ref:`InputEventJoypadButton <class_InputEventJoypadButton>`.
If any function consumes the event, it can call :ref:`Viewport.set_input_as_handled() <class_Viewport_method_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 :ref:`Node._unhandled_input() <class_Node_method__unhandled_input>` callback
will be called if overridden (and not disabled with
:ref:`Node.set_process_unhandled_input() <class_Node_method_set_process_unhandled_input>`).
If any function consumes the event, it can call :ref:`Viewport.set_input_as_handled() <class_Viewport_method_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.
4. If no one wanted the event so far, and a :ref:`Camera3D <class_Camera3D>` is assigned
to the Viewport with :ref:`Object Picking <class_viewport_property_physics_object_picking>` turned on, a ray to the physics world (in the ray direction from
the click) will be cast. (For the root viewport, this can also be enabled in :ref:`Project Settings <class_ProjectSettings_property_physics/common/enable_object_picking>`.) If this ray hits an object, it will call the
:ref:`CollisionObject._input_event() <class_CollisionObject3D_method__input_event>` function in the relevant
physics object (bodies receive this callback by default, but areas do
7. If so far no one consumed the event, the :ref:`Node._unhandled_key_input() <class_Node_method__unhandled_key_input>` callback
will be called if overridden (and not disabled with
:ref:`Node.set_process_unhandled_key_input() <class_Node_method_set_process_unhandled_key_input>`).
This happens only if the event is a :ref:`InputEventKey <class_InputEventKey>`.
If any function consumes the event, it can call :ref:`Viewport.set_input_as_handled() <class_Viewport_method_set_input_as_handled>`, and the
event will not spread any more. The unhandled key input callback is ideal for key events.
8. If no one wanted the event so far, and :ref:`Object Picking <class_viewport_property_physics_object_picking>`
is turned on, the event is used for object picking. For the root viewport, this can also be
enabled in :ref:`Project Settings <class_ProjectSettings_property_physics/common/enable_object_picking>`.
In the case of a 3D scene if a :ref:`Camera3D <class_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 :ref:`CollisionObject3D._input_event() <class_CollisionObject3D_method__input_event>`
function in the relevant physics object (bodies receive this callback by default, but areas do
not. This can be configured through :ref:`Area3D <class_Area3D>` properties).
5. Finally, if the event was unhandled, it will be passed to the next
Viewport in the tree, otherwise it will be ignored.
In the case of a 2D scene, conceptually the same happens with :ref:`CollisionObject2D._input_event() <class_CollisionObject2D_method__input_event>`.
When sending events to all listening nodes within a scene, the viewport
will do so in a reverse depth-first order: Starting with the node at
the bottom of the scene tree, and ending at the root node:
When sending events to its child and descencand 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 embedded Windows
and SubViewports.
.. image:: img/input_event_scene_flow.png
This order doesn't apply to :ref:`Control._gui_input() <class_Control_method__gui_input>`, which uses
a different method based on event location or focused Control.
Since Viewports don't send events to other :ref:`SubViewports <class_SubViewport>`, one of the following
methods has to be used:
1. Use a :ref:`SubViewportContainer <class_SubViewportContainer>`, which automatically
sends events to its child :ref:`SubViewports <class_SubViewport>` during
:ref:`Node._input() <class_Node_method__input>` and :ref:`Node._unhandled_input() <class_Node_method__unhandled_input>`.
2. Implement event propagation based on the indivitual requirements.
GUI events also travel up the scene tree but, since these events target
specific Controls, only direct ancestors of the targeted Control node receive the event.

View File

@@ -38,10 +38,10 @@ Input
-----
:ref:`Viewports <class_Viewport>` are also responsible for delivering properly adjusted and
scaled input events to all their children nodes. Typically, input is received by the
nearest :ref:`Viewport <class_Viewport>` in the tree, but you can set :ref:`Viewports <class_Viewport>` not to receive input by checking
'Disable Input' to 'on'; this will allow the next nearest :ref:`Viewport <class_Viewport>` in the tree to capture
the input.
scaled input events to their children nodes. By default :ref:`SubViewports <class_SubViewport>` don't
automatically receive input, unless they receive it from their direct
:ref:`SubViewportContainer <class_SubViewportContainer>` parent node. In this case, input can be
disabled with the :ref:`Disable Input <class_Viewport_property_gui_disable_input>` property.
.. image:: img/input.png