InputEvent(入力イベント)

それは何ですか?

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

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

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 機能を使用すると、入力アクションを定義し、それらに異なるキーを割り当てることができます。このようにして、同じアクションに対して複数のキーを定義できます(たとえば、キーボードのエスケープキーとゲームパッドのスタートボタン)。その後、コードを更新せずにプロジェクト設定でこのマッピングをより簡単に変更でき、さらにその上にキーマッピング機能を構築して、実行時にゲームがキーマッピングを変更できるようにすることもできます!

InputMap はプロジェクト -> プロジェクト設定 -> インプットマップ の下で設定でき、次のようなアクションを使用できます:

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
    }
}

どのように機能しますか?

すべての入力イベントはユーザー/プレイヤーから発生します(ただし、InputEventを生成してエンジンにフィードバックすることが可能で、ジェスチャーに役立ちます)。各プラットフォームのOSオブジェクトは、デバイスからイベントを読み取り、それらをMainLoopに送ります。SceneTree がデフォルトのMainLoop実装であるため、イベントはそこに送られます。Godot には、現在のSceneTree オブジェクトを取得する、get_tree()関数が用意されています。

しかしSceneTreeはイベントをどう処理するか分からないので、"root" :ref:`Viewport <class_Viewport>`(シーン ツリーの最初のノード)から始まるビューポートにそれを渡します。ビューポートは、受信した入力に対して次のような非常に多くのことを行います:

../../_images/input_event_flow.png
  1. まず、標準の Node._input() 関数は、それをオーバーライドするノードで呼び出されます(そして、Node.set_process_input() で入力処理を無効化していないなら)。いずれかの関数がイベントを消費する場合は、SceneTree.set_input_as_handled() を呼び出すことができ、イベントはそれ以上他に拡散しません。これにより、GUIの前であっても、関心のあるすべてのイベントをフィルタリングできます。ゲームプレイ入力の場合、GUIがイベントを傍受できるため、一般的に Node._unhandled_input() の方が適しています。
  2. 次に、入力をGUIに送り、コントロールがそれを受信できるかどうかを確認します。その場合、Control が仮想関数 Control._gui_input() を介して呼び出され、シグナル "input_event" が発行されます(この関数はスクリプトで継承可能です)。コントロールがイベントを「消費」したい場合、Control.accept_event() を呼び出せば、イベントはそれ以上拡散しません。Control.mouse_filter プロパティを使用して、ControlControl._gui_input() コールバックを介してマウスイベントを通知されるかどうか、およびこれらのイベントがさらに伝播されるかどうかを制御します。
  3. これまでに誰もイベントを消費しなかった場合、未処理入力コールバックがオーバーライドされていれば、それが呼び出されます(そして 、Node.set_process_unhandled_input() で無効化していないなら)。関数がイベントを消費する場合、SceneTree.set_input_as_handled() を呼び出すことができ、イベントはそれ以上拡散しません。未処理入力コールバックは、フルスクリーンのゲームプレイイベントに最適であるため、GUIがアクティブな場合は受信されません。
  4. これまで誰もイベントを望んでおらずCamera がビューポートに割り当てられている場合、物理処理を行う世界への光線(光線の方向はクリックした場所から始まる)が投影されます。この光線がオブジェクトに当たると、関連する物理処理オブジェクトの CollisionObject._input_event() 関数を呼び出します(ボディはデフォルトでこのコールバックを受け取りますが、エリアはそうしません。これは Area プロパティで設定できます)。 (訳注: 要するに画面内のオブジェクトにタッチできるという話です)。
  5. 最後に、イベントが処理されなかった場合、ツリー内の次のビューポートに渡されます。それ以外の場合は無視されます。

シーン内のすべてのリスニングノードにイベントを送信する場合、ビューポートは逆の深さ優先順で送信します。シーンツリーの一番下のノードから始まり、ルートノードで終わります:

../../_images/input_event_scene_flow.png

GUIイベントもシーンツリーを上に移動しますが、これらのイベントは特定のコントロールを対象とするため、ターゲットコントロールノードの直接の先祖のみがイベントを受け取ります。

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

InputEventの構造

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

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

イベント 型インデックス 説明
InputEvent NONE 空の入力イベント。
InputEventKey KEY スキャンコードとユニコードの値、および(Ctrl、Shiftなどの)モディファイヤが含まれています。
InputEventMouseButton MOUSE_BUTTON ボタン、モディファイヤなどのクリック情報が含まれます。
InputEventMouseMotion MOUSE_MOTION 相対位置、絶対位置、速度などのモーション情報が含まれます。
InputEventJoypadMotion JOYSTICK_MOTION ジョイスティック/ジョイパッドのアナログ軸情報が含まれています。
InputEventJoypadButton JOYSTICK_BUTTON ジョイスティック/ジョイパッドのボタン情報が含まれます。
InputEventScreenTouch SCREEN_TOUCH マルチタッチのプレス/リリース情報が含まれています。(モバイルデバイスでのみ使用可能)
InputEventScreenDrag SCREEN_DRAG マルチタッチドラッグ情報が含まれています。(モバイルデバイスでのみ使用可能)
InputEventAction SCREEN_ACTION 汎用アクションが含まれています。これらのイベントは多くの場合、フィードバックとしてプログラマーによって生成されます。(詳細は以下)

アクション

InputEventは、事前定義されたアクションを表す場合と表さない場合があります。アクションは、ゲームロジックをプログラミングするときに入力デバイスを抽象化するので便利です。次の機能が可能になります:

  • 入力が異なるさまざまなデバイス(PCのキーボード、コンソールのJoypadなど)で動作する同じコード。
  • 実行時に再構成される入力。

アクションは、[プロジェクト設定]メニューの[アクション]タブから作成できます。

すべてのイベントには、メソッド 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);

入力マップ

多くの場合、コードからの入力をカスタマイズして再マッピングすることが望まれます。ワークフロー全体がアクションに依存する場合、InputMap シングルトンは、実行時に異なるアクションを再割り当てまたは作成するのに理想的です。このシングルトンは保存されず(手動で変更する必要があります)、そのステートはプロジェクト設定(project.godot)から実行されます。したがって、このタイプの動的システムは、プログラマーが最適と考える方法で設定を保存する必要があります。