Menu
CoddyTech

Señales con argumentos

Parte de la sección Programación orientada a objetos del Journey de GDScript de Coddy. Lección 38 de 65.

Una señal puede transportar valores. Enuméralos en la declaración, como los parámetros de una función:

signal damaged(amount: int, hp_left: int)
signal died

Pasa los valores a emit() en el mismo orden:

func take_damage(amount: int) -> void:
	hp = maxi(hp - amount, 0)
	damaged.emit(amount, hp)
	if hp == 0:
		died.emit()

Una función conectada recibe los valores como parámetros, así que necesita un parámetro por cada valor:

hero.damaged.connect(_on_hero_damaged)

func _on_hero_damaged(amount: int, hp_left: int) -> void:
	print("-%d HP, %d left" % [amount, hp_left])

Los tipos en la declaración documentan los valores: GDScript no los comprueba cuando emites. Una discrepancia aparece en la función receptora. Una función con un número incorrecto de parámetros, o un parámetro tipado que no puede contener el valor, produce un error en la línea de emit(), y esa función no se ejecuta.

bind() añade tus propios valores después de los emitidos. Así, un método puede escuchar a varios héroes y seguir sabiendo cuál recibió el golpe:

ada.damaged.connect(_on_damaged.bind("Ada"))
bo.damaged.connect(_on_damaged.bind("Bo"))

func _on_damaged(amount: int, hp_left: int, who: String) -> void:
	print(who, " lost ", amount, " HP")

Los argumentos proporcionan a un receptor los datos que necesita, para que no tenga que leerlos del emisor. Nunca conectes una lambda que use el propio objeto emisor, como hero.died.connect(func(): print(hero.hp)): la lambda mantiene vivo a hero, hero mantiene la lambda, ninguno de los dos se libera nunca y Godot informa de instancias filtradas cuando termina el programa.

challenge icon

Desafío

Fácil

Una cartera informa de cada cambio mediante señales que incluyen los números. En Wallet, añade los parámetros a ambas señales y escribe los dos métodos:

  • balance_changed(old_balance: int, new_balance: int) y purchase_failed(price: int, missing: int)
  • add(amount) añade monedas y emite balance_changed con el saldo anterior y el posterior.
  • buy(price): cuando el saldo es suficiente, resta el precio y emite balance_changed. De lo contrario, no cambia nada y emite purchase_failed con el precio y la cantidad de monedas que faltan.

El código proporcionado conecta una función a cada señal, lee cuántos comandos siguen, ejecuta cada comando (add 20, buy 15) e imprime las monedas restantes al final. Para add 20, buy 15, buy 10, add 5, buy 10, imprime:

Balance: 0 -> 20
Balance: 20 -> 5
Cannot buy for 10: 5 coins missing
Balance: 5 -> 10
Balance: 10 -> 0
Coins left: 0

Tu código va en wallet.gd. main.gd contiene el código de entrada/salida proporcionado y no se puede editar.

Pruébalo tú mismo

extends Node

func _ready():
	# Código de entrada/salida proporcionado: déjalo tal como está
	var wallet := Wallet.new()
	wallet.balance_changed.connect(_on_balance_changed)
	wallet.purchase_failed.connect(_on_purchase_failed)
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var parts := OS.read_string_from_stdin().split(" ")
		if parts[0] == "add":
			wallet.add(int(parts[1]))
		else:
			wallet.buy(int(parts[1]))
	print("Coins left: ", wallet.balance)

func _on_balance_changed(old_balance: int, new_balance: int) -> void:
	print("Balance: %d -> %d" % [old_balance, new_balance])

func _on_purchase_failed(price: int, missing: int) -> void:
	print("Cannot buy for %d: %d coins missing" % [price, missing])
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de GDScript online