InputEvent (入力イベント)

それは何ですか?

通常、入力の管理は、OSやプラットフォームに関係なく複雑です。これを少し簡単にするために、特別な組み込み型、InputEvent が提供されています。このデータ型は、いくつかのタイプの入力イベントを含むように構成できます。入力イベントはエンジンを通過し、目的に応じて複数の場所で受信できます。

以下に簡単な例を示します。エスケープキーが押された場合にゲームを終了します:

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

ただし、提供されている InputMap 機能を使用する方がより簡単で柔軟です。InputMapは入力アクションを定義し、それらに異なるキーを割り当てることができます。そうすると同じアクションに対して複数のキーを定義できます (キーボードのエスケープキーやゲームパッドのスタートボタンなど)。コードを更新せずに、プロジェクト設定でこのマッピングを簡単に変更でき、その上にキー マッピング機能を構築してゲーム実行時にキー マッピングを変更できるようにすることも可能です!

InputMap は プロジェクト -> プロジェクト設定 -> インプットマップ で設定でき、次のようなスクリプトで入力判定を行うことができます:

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

入力が機能する仕組み

すべての入力イベントはユーザー/プレーヤーから発生します (ただしInputEventを生成してエンジンにフィードバックすることは可能で、それはジェスチャー入力に役立ちます)。各プラットフォームの DisplayServer はオペレーティングシステムからイベントを読み取り、それをルート ウインドウ にフィードします。

ウィンドウの ビューポート は、受信した入力に対して非常に多くの処理を次の順序で実行します。

../../_images/input_event_flow.webp
  1. ビューポートにウインドウが埋め込まれている場合、ビューポートはウィンドウマネージャーの機能でイベントを解釈しようとします (ウィンドウのサイズ変更や移動など)。

  2. 次に埋め込みウィンドウがフォーカスされている場合、イベントはそのウィンドウに送信され、ウインドウビューポートで処理され、その後処理されたものとして処理されます。フォーカスされている埋め込みウィンドウがない場合、イベントは次の順序で現在のビューポートのノードに送信されます。

  3. まず、標準の Node._input() 関数は、それをオーバーライドする (および Node.set_process_input() で入力処理を無効にしていない) ノードで呼び出されます)。いずれかの関数がイベントを消費する場合、その関数は Viewport.set_input_as_handled() を呼び出すことができ、イベントはそれ以上広がりません。これによりGUI の前でも、対象となるすべてのイベントを確実にフィルターできます。ゲームプレイ入力の場合は、GUI がイベントを遮るため、Node._unhandled_input() の方が一般的に適しています。

  4. 次に、入力をGUIに送り、コントロールがそれを受信できるかどうかを確認します。その場合 Control は仮想関数 Control._gui_input() を介して呼び出され、シグナル "gui_input" が発行されます (この関数はスクリプトを継承して作成可能です)。コントロールがイベントを「消費」したい場合は、 Control.accept_event() を呼び出し、イベントはそれ以上広がりません。 Control.mouse_filter プロパティを使用して、 Control._gui_input() コールバックを介して Control にマウス イベントを通知するかどうかを制御します。これらのイベントはさらに伝播されます。

  5. これまで誰もイベントを消費しなかった場合、 Node._shortcut_input() がオーバーライドされていれば呼び出されます (Node.set_process_shortcut_input() で無効になっていない場合)。これは InputEventKeyInputEventShortcutInputEventJoypadButton でのみ発生します。いずれかの関数がイベントを消費する場合、その関数は Viewport.set_input_as_handled() を呼び出すことができ、イベントはそれ以上広がりません。ショートカット入力コールバックは、ショートカットとして意図されたイベントを処理するのに最適です。

  6. これまでに誰もイベントを消費しなかった場合、 Node._unhandled_key_input() がオーバーライドされていれば呼び出されます (Node.set_process_unhandled_key_input() で無効になっていない場合)。これはイベントが InputEventKey の場合にのみ発生します。いずれかの関数がイベントを消費する場合、その関数は Viewport.set_input_as_handled() を呼び出すことができ、イベントはそれ以上広がりません。未処理のキー入力コールバックは、キー イベントに最適です。

  7. これまで誰もイベントを消費しなかった場合、 Node._unhandled_input() がオーバーライドされていれば呼び出されます (Node.set_process_unhandled_input() で無効になっていない場合)。いずれかの関数がイベントを消費する場合、その関数は Viewport.set_input_as_handled() を呼び出すことができ、イベントはそれ以上広がりません。未処理の入力コールバックは全画面ゲームプレイ イベントに最適であるため、GUI がアクティブなときはイベントを受信しません。

  8. これまで誰もイベントを望んでおらず Object Picking がオンになっている場合、イベントはオブジェクトの選択に使用されます。ルートビューポートの場合、これは プロジェクト設定 でも有効にすることができます。 3Dシーンで Camera3D がビューポートに割り当てられている場合、物理世界へのレイ (クリックからの光線方向) がキャストされます。この光線がオブジェクトに当たると、関連する物理オブジェクトの CollisionObject3D._input_event() 関数が呼び出されます。 2D シーンの場合、概念的には同じことが CollisionObject2D._input_event() で起こります。

イベントを子ノードと子孫ノードに送信する場合、ビューポートは次の図に示すように、シーン ツリーの一番下のノードから開始してルート ノードで終わる、深さ優先の逆の順序で送信します。 ウインドウとサブビューポートはこのプロセスから除外されます。

../../_images/input_event_scene_flow.webp

注釈

This order doesn't apply to Control._gui_input(), which uses a different method based on event location or focused Control. GUI mouse events also travel up the scene tree, subject to the Control.mouse_filter restrictions described above. However, since these events target specific Controls, only direct ancestors of the targeted Control node receive the event. GUI keyboard and joypad events do not travel up the scene tree, and can only be handled by the Control that received them. Otherwise, they will be propagated as non-GUI events through Node._unhandled_input().

ビューポートは他の SubViewports にイベントを送信しないため、次のいずれかのメソッドを使用する必要があります。

  1. SubViewportContainer を使用します。これは Node._input() または Control._gui_input() の後に、その子の SubViewports にイベントを自動的に送信します。

  2. 個々の要件に基づいてイベントの伝播を実装します。

Godotのノードベースの設計に従って、特殊な子ノードが特定のイベントを処理および消費できるようになり、祖先や最終的にはシーンルートが必要に応じてより一般化された動作を提供できるようになります。

InputEventの構造

InputEvent は単なる基本組み込み型であり、何も表さず、イベントID(イベントごとに増加する)、デバイスインデックスなどの基本情報のみを含みます。

InputEventにはいくつかの特殊なタイプがあり、次の表で説明します:

イベント

説明

InputEvent

空の入力イベント。

InputEventKey

キーコードとUnicode値、および修飾子が含まれます。

InputEventMouseButton

ボタン、モディファイヤなどのクリック情報が含まれます。

InputEventMouseMotion

相対位置、絶対位置、速度などのモーション情報が含まれます。

InputEventJoypadMotion

ジョイスティック/ジョイパッドのアナログ軸情報が含まれています。

InputEventJoypadButton

ジョイスティック/ジョイパッドのボタン情報が含まれます。

InputEventScreenTouch

マルチタッチのプレス/リリース情報が含まれています。(モバイルデバイスでのみ使用可能)

InputEventScreenDrag

マルチタッチドラッグ情報が含まれています。(モバイルデバイスでのみ使用可能)

InputEventMagnifyGesture

位置、ファクター情報、および修飾子が含まれます。

InputEventPanGesture

位置、差分情報、および修飾子が含まれます。

InputEventMIDI

MIDI関連の情報が含まれます。

InputEventShortcut

ショートカット情報が含まれます。

InputEventAction

汎用アクションが含まれています。これらのイベントは多くの場合、フィードバックとしてプログラマーによって生成されます。(詳細は以下)

Input actions

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

これにより、次のことが可能になります。

  • 入力が異なるさまざまなデバイス(PCのキーボード、コンソールのゲームパッドなど)で動作する同じコード。

  • Input to be reconfigured at runtime.

  • Actions to be triggered programmatically at runtime.

アクションは プロジェクト設定メニューの インプットマップ タブから作成し、入力イベントを割り当てることができます。

Any event has the methods InputEvent.is_action(), InputEvent.is_pressed() and InputEvent.is_echo().

あるいは、ゲームコードからのアクションをゲームに返すことが望ましい場合があります(この良い例は、ジェスチャの検出です)。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)

参考

See 入力アクションの作成 for a tutorial on adding input actions in the project settings.

インプットマップ

Customizing and re-mapping input from code is often desired. If your whole workflow depends on actions, the InputMap singleton is ideal for reassigning or creating different actions at runtime. This singleton is not saved (must be modified manually) and its state is run from the project settings (project.godot). So any dynamic system of this type needs to store settings in the way the programmer best sees fit.