Signale mit Argumenten
Teil des Abschnitts Objektorientierte Programmierung der GDScript-Journey von Coddy. Lektion 38 von 65.
Ein Signal kann Werte übertragen. Liste sie in der Deklaration auf, wie die Parameter einer Funktion:
signal damaged(amount: int, hp_left: int)
signal diedÜbergib die Werte in derselben Reihenfolge an emit():
func take_damage(amount: int) -> void:
hp = maxi(hp - amount, 0)
damaged.emit(amount, hp)
if hp == 0:
died.emit()Eine verbundene Funktion erhält die Werte als Parameter und benötigt daher einen Parameter pro Wert:
hero.damaged.connect(_on_hero_damaged)
func _on_hero_damaged(amount: int, hp_left: int) -> void:
print("-%d HP, %d left" % [amount, hp_left])Die Typen in der Deklaration dokumentieren die Werte: GDScript prüft sie beim Auslösen nicht. Eine Typabweichung zeigt sich in der empfangenden Funktion. Eine Funktion mit der falschen Anzahl von Parametern oder einem typisierten Parameter, der den Wert nicht aufnehmen kann, verursacht einen Fehler an der Zeile mit emit(), und die Funktion wird nicht ausgeführt.
bind() fügt nach den ausgegebenen Werten eigene Werte hinzu. Eine Methode kann dann mehreren Helden zuhören und trotzdem wissen, welcher getroffen wurde:
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")Argumente liefern einem Listener die benötigten Daten, sodass er sie nicht vom Emitter auslesen muss. Verbinde niemals eine Lambda-Funktion, die das auslösende Objekt selbst verwendet, zum Beispiel hero.died.connect(func(): print(hero.hp)): Die Lambda-Funktion hält hero am Leben, hero hält die Lambda-Funktion, keines von beiden wird jemals freigegeben, und Godot meldet beim Beenden des Programms Speicherlecks.
Aufgabe
EinfachEine Wallet meldet jede Änderung mit Signalen, die die Zahlen enthalten. Füge in Wallet die Parameter zu beiden Signalen hinzu und schreibe die beiden Methoden:
balance_changed(old_balance: int, new_balance: int)undpurchase_failed(price: int, missing: int)add(amount)fügt Münzen hinzu und sendetbalance_changedmit dem Kontostand davor und danach aus.buy(price): Wenn der Kontostand ausreicht, ziehe den Preis ab und sendebalance_changedaus. Andernfalls ändere nichts und sendepurchase_failedmit dem Preis und der Anzahl der fehlenden Münzen aus.
Der bereitgestellte Code verbindet jeweils eine Funktion mit jedem Signal, liest ein, wie viele Befehle folgen, führt jeden Befehl aus (add 20, buy 15) und gibt am Ende die übrigen Münzen aus. Für add 20, buy 15, buy 10, add 5, buy 10 gibt er Folgendes aus:
Balance: 0 -> 20
Balance: 20 -> 5
Cannot buy for 10: 5 coins missing
Balance: 5 -> 10
Balance: 10 -> 0
Coins left: 0Dein Code gehört in wallet.gd. main.gd enthält den bereitgestellten Ein-/Ausgabecode und kann nicht bearbeitet werden.
Probier es selbst
extends Node
func _ready():
# Vorgegebener Ein-/Ausgabecode: unverändert lassen
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])
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas Schlüsselwort selfMethodenEigenschaftenKonstruktor (_init)Wiederholung – Einfacher Taschenrechner4Polymorphie
Methodenüberschreibung erneut betrachtetDuck-TypisierungAbstrakte Klassen und MethodenSchnittstellendesignRückblick – Formrechner7Signale
Was ist ein Signal?Deklarieren und AuslösenMit Signalen verbindenSignale mit ArgumentenRückblick – Gesundheitssystem2Klassenattribute
Instanz- vs. statische VariablenStatische FunktionenProperty-SetterProperty-GetterPrivat nach KonventionWiederholung – Bankkontenverwaltung5Kapselung
Öffentliche und private MemberValidierung mit SetternInformationsverbergenSchreibgeschützte EigenschaftenRückblick – System zur Schülerverwaltung8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungInnere KlassenNodes als KomponentenRefCounted vs. NodeEnums in Klassen11Projekt: Bibliotheksverwaltung
ProjektübersichtBuch- und Benutzerklassen3Vererbung
Grundlegende VererbungDas Schlüsselwort superMethodenüberschreibungVererbungskettenTypprüfungen mit isWiederholung – Mitarbeiterhierarchie6Spezielle Methoden
Einführung in virtuelle MethodenDie _to_string-MethodeBenutzerdefinierte IteratorenRückblick – Benutzerdefinierte Liste9Entwurfsmuster Teil 1
Einführung in EntwurfsmusterSingleton-MusterFactory-MusterBeobachter-MusterStrategie-Muster12Abschließende Herausforderungen
E-Learning-PlattformBankensystemEntwicklung von SpielfigurenFahrzeugvermietungÜbe selbstständig: Online-GDScript-Compiler