シグナルへの接続
CoddyのGDScriptジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 37/65。
connect() は、実行する関数を Callable として受け取ります。括弧を付けずにメソッド名を書くか、ラムダを書きます。
chest.opened.connect(_on_chest_opened) # このスクリプトのメソッド
chest.opened.connect(quest_log.add_entry) # 別のオブジェクトのメソッド
chest.opened.connect(func(): print("Creak!")) # ラムダ式Godotでは、リスニングメソッドを_on_、次に発信元、最後にシグナルの順に命名します。たとえば_on_chest_openedです。1つのシグナルに複数の関数を接続でき、それらは接続された順に実行されます。
イベントを監視するオブジェクトは通常、発信元を受け取るメソッド内で、自身を接続します:
# quest_log.gd
class_name QuestLog
extends RefCounted
var chests_opened := 0
func track(chest: Chest) -> void:
if not chest.opened.is_connected(_on_chest_opened):
chest.opened.connect(_on_chest_opened)
func untrack(chest: Chest) -> void:
if chest.opened.is_connected(_on_chest_opened):
chest.opened.disconnect(_on_chest_opened)
func _on_chest_opened() -> void:
chests_opened += 1同じ関数を同じシグナルに2回接続するのはエラーです。また、接続されていない関数を切断するのもエラーです。まずis_connected()で確認します。disconnect()は監視を停止し、次にシグナルを発行してもその関数は実行されなくなります。
2 番目の引数として CONNECT_ONE_SHOT を渡すと、接続は最初の呼び出しの後に解除されます: chest.opened.connect(_on_first_open, CONNECT_ONE_SHOT)。
ラムダは、作成された時点でローカル変数が持っていた値を保持します。接続されたラムダ内の count += 1 はそのコピーを変更しますが、_ready() 内の count は 0 のままです。QuestLog のように、リスナーオブジェクトのメンバー変数にカウンターを保持してください。
チャレンジ
簡単射撃場には、撃たれると hit を発するターゲットがあります。ターゲットを監視する ScoreBoard を作成してください。
watch(target)は、ターゲットのhitシグナルを_on_target_hitに接続します。すでに監視中のターゲットを監視しても、何も変わりません。ignore(target)は接続を解除します。監視していないターゲットを無視しても、何も変わりません。_on_target_hit()はpointsに10を加算し、Hit! Score: Nを出力します。
同じターゲットを2回監視したり、監視していないターゲットを無視したりしても、エラーが発生してはいけません。エラーがあるとテストに失敗するためです。target.gd は完成しています。
提供されたコードはターゲットの数を読み込んだ後、watch 0、ignore 0、shoot 0 のようなコマンドを読み込み、最終スコアを出力します。ターゲットが2つあり、コマンドが watch 0、shoot 0、shoot 1、watch 1、watch 1、shoot 1、ignore 0、shoot 0 の場合、次のように出力されます。
Shot target 0
Hit! Score: 10
Shot target 1
Shot target 1
Hit! Score: 20
Shot target 0
Final score: 20コードは score_board.gd と target.gd に記述します。main.gd には提供された入出力コードがあり、編集できません。
自分で試してみよう
extends Node
func _ready():
# 提供された入出力コード: そのままにしておいてください
var board := ScoreBoard.new()
var targets: Array[Target] = []
for i in int(OS.read_string_from_stdin()):
targets.append(Target.new())
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ")
var target := targets[int(parts[1])]
if parts[0] == "watch":
board.watch(target)
elif parts[0] == "ignore":
board.ignore(target)
else:
print("Shot target ", parts[1])
target.shoot()
print("Final score: ", board.points)
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
自分で練習してみよう: GDScriptオンラインコンパイラ