シグナル

はじめに

シグナルは、observerパターンのGodotバージョンです。これにより、ノードは、他のノードが聞いて応答できるメッセージを送信できます。例えば、ボタンが押されているかどうかを継続的に確認するのではなく、ボタンが押されたときに信号を発することができます。

注釈

オブザーバーパターンの詳細については、以下をご覧ください: http://gameprogrammingpatterns.com/observer.html

シグナルは、ゲームオブジェクトを分離する方法であり、コードの整理と管理が容易になります。ゲームオブジェクトに他のオブジェクトが常に存在することを強制するのではなく、代わりに、関心のあるすべてのオブジェクトが申請および応答できるシグナルを発信できます。

以下に、独自のプロジェクトでシグナルを使用する方法の例をいくつか示します。

タイマーの例

シグナルがどのように機能するかを見るために、:ref: Timer <class_Timer>ノードを使用してみましょう。 Node2Dと2つの子:Timerと:ref: Sprite <class_Sprite>で新しいシーンを作成します。 Sceneドックで、Node2Dの名前をTimerExampleに変更します。

スプライトのテクスチャには、Godotアイコン、またはその他の好きな画像を使用できます。そのためには、スプライトのテクスチャ属性ドロップダウンメニューで 読込み を選択します。ルートノードにスクリプトを添付しますが、まだコードを追加しないでください。

シーンツリーは次のようになります:

../../_images/signals_node_setup.png

Timerノードのプロパティで、Autostartの横にある「オン」ボックスをクリックします。これにより、シーンの実行時にタイマーが自動的に開始されます。Wait Timeは1秒のままにしておきましょう。

「インスペクタ」タブの隣には、「ノード」というラベルの付いたタブがあります。 このタブをクリックすると、選択したノードが発信できるすべての信号が表示されます。 Timerノードの場合、関係するのは「timeout」です。 このシグナルは、タイマーが 0 に到達するたびに出力されます。

../../_images/signals_node_tab_timer.png

シグナルパネルの下にある「timeout()」シグナルをクリックし、「接続...」をクリックします。 次のウィンドウが表示され、信号の接続方法を定義できます:

../../_images/signals_connect_dialog_timer.png

左側でシーンのノードを見ることができます。信号として「監視」したいノードを選択できます。タイマーノードは青色で、ノードが信号を発していること意味します。ルートノードを選択してください。

警告

ターゲットノードにはスクリプトが添付されている必要があります。そうしないと、エラーメッセージが表示されます。

ウィンドウの下部には、「Method In Node」というラベルのフィールドがあります。 これは、使用したいターゲットノードのスクリプト内の関数の名前です。 デフォルトでは、Godotは_on_<ノード名>_<シグナル名>という命名規則を使用してこの関数を作成しますが、必要に応じて変更できます。

「接続」をクリックすると、スクリプトで関数が作成されたことがわかります:

extends Node2D

func _on_Timer_timeout():
    pass # replace with function body
public class TimerExample : Node2D
{
    private void _on_Timer_timeout()
    {
        // Replace with function body.
    }
}

これで、仮置きのコードを、シグナルの受信時に実行したいコードに置き換えることができます。 スプライトを点滅させましょう:

extends Node2D

func _on_Timer_timeout():
    # Note: the `$` operator is a shorthand for `get_node()`,
    # so `$Sprite` is equivalent to `get_node("Sprite")`.
    $Sprite.visible = !$Sprite.visible
public class TimerExample : Node2D
{
    public void _on_Timer_timeout()
    {
        var sprite = GetNode<Sprite>("Sprite");
        sprite.Visible = !sprite.Visible;
    }
}

シーンを実行すると、スプライトが1秒ごとに点滅します。 これを変更するには、タイマーのWait Timeプロパティを変更します。

コード内でシグナルをを接続する

エディタではなくコードでシグナル接続を行うこともできます。 これは通常、コードを介してノードをインスタンス化するときに必要であり、エディタを使用して接続することはできません。

まず、タイマーの[ノード]タブで接続を選択し、[切断]をクリックして、シグナルを切断します。

../../_images/signals_disconnect_timer.png

コードで接続するために、connect関数を使用できます。接続が実行時に行われるように、その関数を_ready()に入れます。関数の構文は <source_node>.connect(<signal_name>, <target_node>, <target_function_name>) です。タイマー接続のコードは次のとおりです:

extends Node2D

func _ready():
    $Timer.connect("timeout", self, "_on_Timer_timeout")

func _on_Timer_timeout():
    $Sprite.visible = !$Sprite.visible
public class TimerExample : Node2D
{
    public override void _Ready()
    {
        GetNode("Timer").Connect("timeout", this, nameof(_on_Timer_timeout));
    }

    public void _on_Timer_timeout()
    {
        var sprite = GetNode<Sprite>("Sprite");
        sprite.Visible = !sprite.Visible;
    }
}

カスタムシグナル

Godotで独自のカスタムシグナルを宣言することもできます:

extends Node2D

signal my_signal
public class Main : Node2D
{
    [Signal]
    public delegate void MySignal();
}

一度宣言すると、カスタムシグナルがインスペクターに表示され、ノードの組み込みシグナルと同じ方法で接続できます。

コードを介してシグナルを発信するには、 emit_signal 関数を使用します:

extends Node2D

signal my_signal

func _ready():
    emit_signal("my_signal")
public class Main : Node2D
{
    [Signal]
    public delegate void MySignal();

    public override void _Ready()
    {
        EmitSignal(nameof(MySignal));
    }
}

結論

Godotの組み込みノードタイプの多くは、イベントの検出に使用できる信号を提供します。 たとえば、コインの見た目をしたArea2Dは、プレイヤーの物理ボディが衝突形状に入るたびに body_entered シグナルを発し、プレイヤーがそれを収集したタイミングを知ることができます。

次のセクション最初のゲームでは、さまざまなゲームコンポーネントを接続するシグナルのいくつかの使用法を含む、完全なゲームを構築します。