Signals with Arguments
Part of the Object Oriented Programming section of Coddy's GDScript journey. Lesson 38 of 65.
A signal can carry values. List them in the declaration, like the parameters of a function:
signal damaged(amount: int, hp_left: int)
signal diedPass the values to emit() in the same order:
func take_damage(amount: int) -> void:
hp = maxi(hp - amount, 0)
damaged.emit(amount, hp)
if hp == 0:
died.emit()A connected function receives the values as its parameters, so it needs one parameter per value:
hero.damaged.connect(_on_hero_damaged)
func _on_hero_damaged(amount: int, hp_left: int) -> void:
print("-%d HP, %d left" % [amount, hp_left])The types in the declaration document the values: GDScript does not check them when you emit. A mismatch shows up in the receiving function. A function with the wrong number of parameters, or a typed parameter that cannot hold the value, is an error at the emit() line, and that function does not run.
bind() adds values of your own after the emitted ones. One method can then listen to several heroes and still know which one was hit:
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")Arguments give a listener the data it needs, so it does not have to read it from the emitter. Never connect a lambda that uses the emitting object itself, such as hero.died.connect(func(): print(hero.hp)): the lambda keeps hero alive, hero keeps the lambda, neither is ever freed, and Godot reports leaked instances when the program ends.
Challenge
EasyA wallet reports every change with signals that carry the numbers. In Wallet, add the parameters to both signals and write the two methods:
balance_changed(old_balance: int, new_balance: int)andpurchase_failed(price: int, missing: int)add(amount)adds coins and emitsbalance_changedwith the balance before and after.buy(price): when the balance is enough, subtract the price and emitbalance_changed. Otherwise change nothing and emitpurchase_failedwith the price and how many coins are missing.
The supplied code connects one function to each signal, reads how many commands follow, runs each command (add 20, buy 15) and prints the coins left at the end. For add 20, buy 15, buy 10, add 5, buy 10 it prints:
Balance: 0 -> 20
Balance: 20 -> 5
Cannot buy for 10: 5 coins missing
Balance: 5 -> 10
Balance: 10 -> 0
Coins left: 0Your code goes in wallet.gd. main.gd holds the supplied input/output code and cannot be edited.
Try it yourself
extends Node
func _ready():
# Supplied input/output code: keep it as it is
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])
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe self KeywordMethodsPropertiesConstructor (_init)Recap - Simple Calculator4Polymorphism
Method Overriding RevisitedDuck TypingAbstract Classes and MethodsInterface DesignRecap - Shape Calculator7Signals
What is a Signal?Declaring and EmittingConnecting to SignalsSignals with ArgumentsRecap - Health System2Class Properties
Instance vs Static VariablesStatic FunctionsProperty SettersProperty GettersPrivate by ConventionRecap - Bank Account Manager5Encapsulation
Public and Private MembersValidation with SettersInformation HidingRead-Only PropertiesRecap - Student Records System8Advanced OOP Concepts
Composition vs InheritanceInner ClassesNodes as ComponentsRefCounted vs NodeEnums in Classes11Project: Library Management
Project OverviewBook and User Classes3Inheritance
Basic InheritanceThe super KeywordMethod OverridingInheritance ChainsType Checks with isRecap - Employee Hierarchy6Special Methods
Virtual Methods IntroductionThe _to_string MethodCustom IteratorsRecap - Custom List9Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy PatternPractice on your own: Online GDScript compiler