Up to date

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

Instanciando con señales

Las señales proporcionan una forma de desacoplar objetos del juego, permitiéndote evitar forzar una disposición fija de nodos. Una señal puede ser necesaria cuando te encuentras utilizando get_parent(). Hacer referencia directamente al padre de un nodo significa que no puedes mover fácilmente ese nodo a otra ubicación en el árbol de escena. Esto puede ser especialmente problemático cuando estás instanciando objetos en tiempo de ejecución y deseas colocarlos en una ubicación arbitraria en el árbol de escena en ejecución.

A continuación, consideraremos un ejemplo de tal situación: disparar proyectiles (balas).

Ejemplo de disparos

Consideremos un personaje que pueda rotar y disparar en dirección al ratón. Cada vez que el botón del ratón sea presionado, creamos una instancia de la bala en la ubicación del jugador. Ver Creando instancias para más detalles.

Utilizaremos un Area2D para representar la bala, que se mueve en línea recta a una velocidad determinada:

extends Area2D

var velocity = Vector2.RIGHT

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

Sin embargo, si las balas son añadidas como hijas del jugador, entonces permanecerán "ligadas" al jugador a medida que gira:

../../_images/signals_shoot1.gif

En su lugar, necesitamos que las balas sean independientes del movimiento del jugador - una vez disparadas, deberían continuar viajando en línea recta y el jugador ya no puede afectarlas. En vez de ser añadidas al árbol de escenas como un hijo del jugador, tiene más sentido añadir la bala como un hijo de la escena de juego "principal", la cual puede ser el padre del jugador o incluso más arriba en el árbol.

Podrías hacer esto agregando la bala directamente a la escena principal:

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

Sin embargo, esto conducirá a un problema diferente. Ahora, si intentas probar tu escena "Player" de forma independiente, se bloqueará al disparar, porque no hay ningún nodo padre al que pueda acceder. Esto hace que sea mucho más difícil probar el código del jugador de forma independiente y también significa que si decides cambiar la estructura del nodo de la escena principal, es posible que el padre del jugador ya no sea el nodo apropiado para recibir las balas.

La solución a esto es usar una señal para "emitir" las balas desde el jugador. El jugador entonces no tiene necesidad de "saber" qué pasa con las balas después de eso - cualquier nodo que esté conectado a la señal puede "recibir" las balas y tomar la acción apropiada para generarlas.

Este es el código para el jugador usando señales para emitir la bala:

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())

En la escena princial, contectaremos la señal del jugador (aparecerá en la pestaña "Nodo")

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)

Ahora las balas mantendrán su propio movimiento independiente de la rotación del jugador:

../../_images/signals_shoot2.gif