引数付きシグナル
CoddyのGDScriptジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 38/65。
シグナルは値を渡すことができます。関数のパラメーターのように、宣言に値を列挙します。
signal damaged(amount: int, hp_left: int)
signal died値を同じ順序でemit()に渡します。
func take_damage(amount: int) -> void:
hp = maxi(hp - amount, 0)
damaged.emit(amount, hp)
if hp == 0:
died.emit()接続された関数は値を引数として受け取るため、値ごとに1つの引数が必要です。
hero.damaged.connect(_on_hero_damaged)
func _on_hero_damaged(amount: int, hp_left: int) -> void:
print("-%d HP, %d left" % [amount, hp_left])宣言内の型は値を記録するものです。GDScriptはシグナルを発行するときに型をチェックしません。不一致は受信側の関数で明らかになります。パラメーターの数が間違っている関数や、値を格納できない型付きパラメーターがある場合、emit() の行でエラーになり、その関数は実行されません。
bind()は、発行された値の後に独自の値を追加します。1つのメソッドで複数のヒーローを監視しながら、誰がダメージを受けたのかを把握できます。
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")引数を使うと、リスナーは必要なデータを受け取れるため、エミッターから読み取る必要がありません。hero.died.connect(func(): print(hero.hp)) のように、発行元オブジェクト自体を使うラムダを接続してはいけません。ラムダが hero を保持し、hero がラムダを保持するため、どちらも解放されず、プログラムの終了時に Godot がリークしたインスタンスを報告します。
チャレンジ
簡単ウォレットは、数値を伴うシグナルで変更を通知します。Walletに、両方のシグナルのパラメーターを追加し、2つのメソッドを記述してください。
balance_changed(old_balance: int, new_balance: int)とpurchase_failed(price: int, missing: int)add(amount)はコインを追加し、変更前と変更後の残高をbalance_changedで通知します。buy(price):残高が足りている場合は、価格分を差し引き、balance_changedで通知します。それ以外の場合は何も変更せず、価格と不足しているコインの数をpurchase_failedで通知します。
用意されているコードは、各シグナルに1つずつ関数を接続し、後に続くコマンドの数を読み取り、各コマンド(add 20、buy 15)を実行して、最後に残っているコインを表示します。add 20、buy 15、buy 10、add 5、buy 10の場合、次のように表示されます。
Balance: 0 -> 20
Balance: 20 -> 5
Cannot buy for 10: 5 coins missing
Balance: 5 -> 10
Balance: 10 -> 0
Coins left: 0コードはwallet.gdに記述してください。main.gdには用意されている入出力コードが含まれており、編集できません。
自分で試してみよう
extends Node
func _ready():
# 提供された入出力コード:そのままにしてください
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])
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: GDScriptオンラインコンパイラ