Up to date

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

Instancing with signals

Signals provide a way to decouple game objects, allowing you to avoid forcing a fixed arrangement of nodes. One sign that a signal might be called for is when you find yourself using get_parent(). Referring directly to a node's parent means that you can't easily move that node to another location in the scene tree. This can be especially problematic when you are instancing objects at runtime and may want to place them in an arbitrary location in the running scene tree.

Below we'll consider an example of such a situation: firing bullets.

발사 예제

Consider a player character that can rotate and shoot towards the mouse. Every time the mouse button is clicked, we create an instance of the bullet at the player's location. See 인스턴스 만들기 for details.

We'll use an Area2D for the bullet, which moves in a straight line at a given velocity:

extends Area2D

var velocity = Vector2.RIGHT

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

하지만, 총알이 플레이어의 자손으로 추가된다면, 플레이어가 회전하는 것에 따라 "붙어있는 채로" 남아있을 것입니다:

../../_images/signals_shoot1.gif

대신, 총알을 플레이어의 움직임에 독립하도록 해야 합니다 - 일단 발사가 되면, 플레이어가 그것에 영향을 주지 않고 직선으로 계속 나아가야 합니다. 플레이어의 자손으로 씬 트리에 추가하는 대신, 총알을 "메인" 게임 씬의 자손으로 추가하는 것이 더 합리적입니다, 이렇게 하면 총알이 플레이어의 부모나 더 위로 올라갈 수도 있습니다.

You could do this by adding the bullet to the main scene directly:

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

However, this will lead to a different problem. Now if you try to test your "Player" scene independently, it will crash on shooting, because there is no parent node to access. This makes it a lot harder to test your player code independently and also means that if you decide to change your main scene's node structure, the player's parent may no longer be the appropriate node to receive the bullets.

해결책은 플레이어로부터 총알을 "방출"하는 시그널을 사용하는 것입니다. 그렇게 하면 플레이어는 총알이 어떻게 되는지 "알" 필요가 없습니다 - 이 시그널에 연결된 어떤 노드라도 총알을 "받을" 수 있고 총알을 스폰하기 위한 적절한 행동을 취해줄 수 있습니다.

이것이 시그널을 사용해 플레이어가 총알을 방출하는 코드입니다:

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