Up to date

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

シグナルによるインスタンス化

シグナルは、ゲームオブジェクトを分離する方法を提供し、ノードの固定配置を強制することを回避できます。シグナルが必要となる兆候の1つは、get_parent() を使用して自分自身を見つけたときです。ノードの親を直接参照するということは、そのノードをシーンツリー内の別の場所に簡単に移動できないことを意味します。これは、実行時にオブジェクトをインスタンス化し、実行中のシーンツリーの任意の場所に配置する場合に特に問題になる可能性があります。

以下に、そのような状況の例を考えます: 弾丸を発射します。

発射処理の例

マウスに向かって回転して弾を撃つことができるプレイヤーキャラクターを考えてみましょう。マウスボタンがクリックされるたびに、プレイヤーの場所に弾丸のインスタンスが作成されます。詳細については、インスタンスの作成 を参照してください。

弾丸には Area2D を使用します。これは、指定された速度で直線的に移動します:

extends Area2D

var velocity = Vector2.RIGHT

func _physics_process(delta):
    position += velocity * delta

ただし、弾丸がプレイヤーの子として追加された場合、プレイヤーが回転したときに、弾丸も「アタッチ」されたままになります:

../../_images/signals_shoot1.gif

代わりに、弾丸はプレイヤーの動きから独立している必要があります。発射されたら、弾丸は直線で移動し続ける必要があり、プレイヤーは弾丸に影響を与えることができなくなります。プレイヤーの子としてシーンツリーに追加する代わりに、弾丸をプレイヤーの親またはツリーのさらに上位にある「メイン」ゲームシーンの子として追加する方が理にかなっています。

これを行うには、弾丸をメインシーンに直接追加します:

var bullet_instance = Bullet.instantiate()
get_parent().add_child(bullet_instance)

ただし、これは別の問題につながります。 「プレイヤー」シーンを個別にテストしようとすると、(弾丸の追加先として)アクセスする親ノードがないため、確認時にクラッシュします。これにより、プレイヤーコードを個別にテストすることが非常に難しくなります。また、メインシーンのノード構造を変更する場合、プレイヤーの親が弾丸を受け取る適切なノードではなくなる可能性があります。

これに対する解決策は、プレイヤーから弾丸を「放出」するシグナルを使用することです。プレイヤーはその後、弾丸に何が起こるかを「知る」必要はありません - シグナルに接続されているノードは、弾丸を「受信」し、弾丸を発生させるために適切なアクションを実行できます。

シグナルを使用して弾丸を発射するプレイヤーのコードは次のとおりです:

extends Sprite2D

signal shoot(bullet, direction, location)

var Bullet = preload("res://bullet.tscn")

func _input(event):
    if event is InputEventMouseButton:
        if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
            shoot.emit(Bullet, rotation, position)

func _process(delta):
    look_at(get_global_mouse_position())

In the main scene, we then connect the player's signal (it will appear in the "Node" tab of the Inspector)

func _on_player_shoot(Bullet, direction, location):
    var spawned_bullet = Bullet.instantiate()
    add_child(spawned_bullet)
    spawned_bullet.rotation = direction
    spawned_bullet.position = location
    spawned_bullet.velocity = spawned_bullet.velocity.rotated(direction)

これで、弾丸はプレイヤーの回転に関係なく独自の動きを維持します:

../../_images/signals_shoot2.gif