Communityコーディング&開発github.com

ziva-sh/godot-signals

Godot 4 のシグナルパターンとその失敗モードについて - 型付きシグナルの宣言、emit()、Callable を用いた connect() と disconnect()、bind() と unbind()、ラムダ、CONNECT_ONE_SHOT と CONNECT_DEFERRED、シグナルとタイマーの await、.tscn ファイルに保存されるエディタ接続、そして「呼び下げ、シグナル上げ」のルールを解説します。UI ボタン、タイマー、Area2D やボディイベント、カスタムゲームイベントの配線、Godot 3 の connect("signal", self, "method") や yield コードの置き換え、あるいは「already connected」のデバッグ時に使用します。

godot-signals とは?

このスキルは、Godot 4 におけるシグナルシステムの完全なガイドです。型付きシグナルの宣言、emit() による発行、Callable を使用した connect() と disconnect() の正しい方法、bind() と unbind() による引数の操作、ラムダや CONNECT_ONE_SHOT、CONNECT_DEFERRED のような接続フラグ、そして await キーワードを使った非同期処理のパターンを網羅しています。また、エディタ上で作成された接続が .tscn ファイルにどのように保存されるか、そして「呼び下げ、シグナル上げ」の設計ルールについても詳しく説明します。このスキルは、特に UI ボタンやタイマー、Area2D のボディエントリなどのイベント処理、カスタムゲームイベントの実装、そして Godot 3 からの移行作業(古い connect() や yield の置き換え)を行う開発者にとって不可欠です。さらに、接続の重複や解放されたオブジェクトへの参照など、よくある落とし穴とそのデバッグ方法についても扱い、タイプセーフで堅牢なコードを書くための実践的なアドバイスを提供します。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ziva-sh/godot-skills/tree/HEAD/skills/godot-signals

Installed? Explore more コーディング&開発 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Godot 4 のシグナル

Godot 4 では、シグナルは第一級の Signal 値であり、メソッド参照は Callable です。すべての場面でオブジェクト構文(button.pressed.connect(_on_pressed))を使用してください。これにより、パーサーがスペルミスのハンドラや、self に対するスペルミスのシグナルを拒否します。型付けされた他のノードに対するスペルミスのシグナルは、unsafe_property_access がエラーに設定されている場合にキャッチされます(godot-4-api-pitfalls スキルを参照)。文字列形式(connect("pressed", ...)、emit_signal("died"))は実行時にのみチェックされます。

宣言、発行、接続

extends Node

signal health_changed(old_value: int, new_value: int)
signal died

var health := 100


func take_damage(amount: int) -> void:
	var old := health
	health = maxi(health - amount, 0)
	health_changed.emit(old, health)
	if health == 0:
		died.emit()
extends Control

@onready var start_button: Button = %StartButton
@onready var quit_button: Button = %QuitButton


func _ready() -> void:
	start_button.pressed.connect(_on_start_pressed)
	quit_button.pressed.connect(get_tree().quit)
	start_button.mouse_entered.connect(func() -> void: start_button.grab_focus())


func _on_start_pressed() -> void:
	get_tree().change_scene_to_file("res://level_1.tscn")

ハンドラは、シグナルが発行する引数を正確に受け入れなければなりません。不一致はパースエラーではありません。発行時に Godot は Error calling from signal 'x' to callable: '...': Method expected 0 argument(s), but called with 1. をログに記録し、ハンドラをスキップします。

bind() と unbind()

  • bind(a, b) は、シグナル自身の引数の後に追加の引数を追加します。pressed のハンドラが 1 つの値でバインドされている場合、1 つのパラメータを受け取ります。health_changed(old, new) が 1 つの値でバインドされている場合、old, new, bound の順序で 3 つのパラメータを受け取ります。
  • unbind(n) は、最後の n 個のシグナル引数を削除するため、引数なしの関数でも引数を送信するシグナルを処理できます。
extends HBoxContainer

signal slot_chosen(index: int)

var slot_buttons: Array[Button] = []


func _ready() -> void:
	for i in 4:
		var button := Button.new()
		button.text = "Slot %d" % (i + 1)
		add_child(button)
		slot_buttons.append(button)
		button.pressed.connect(_on_slot_pressed.bind(i))
	var timer := Timer.new()
	add_child(timer)
	timer.timeout.connect(_refresh)
	slot_chosen.connect(_refresh.unbind(1))
	timer.start(1.0)


func _on_slot_pressed(index: int) -> void:
	slot_chosen.emit(index)


func _refresh() -> void:
	for button in slot_buttons:
		button.disabled = false

切断、重複、ワンショット接続

  • disconnect() には、接続されたものと等しい Callable が必要です。再度構築された _handler.bind(1) は等しいと比較され、機能します。ラムダはそうではありません。変数に保持し、その変数を切断してください。
  • 同じ Callable を 2 回接続すると、Signal 'x' is already connected to given callable ... とログに記録され、1 つの接続が維持されます。コードが 2 回実行される可能性がある場合(例えば、ツリーに再追加されるノードの _ready() 内)、is_connected() でガードしてください。
  • connect(callable, CONNECT_ONE_SHOT) は、最初の発行後に切断します。CONNECT_DEFERRED は、アイドル時にハンドラを実行します。物理コールバック(body_entered など)が物理状態を変更する場合に、これ(または set_deferred())を使用してください。直接変更すると、Can't change this state while flushing queries. とログに記録されます。
  • オブジェクトへの接続は、そのオブジェクトが解放されると削除されます。
extends Area2D

@onready var shape: CollisionShape2D = $CollisionShape2D
var _on_first_touch := func(body: Node2D) -> void: print(body.name, " touched first")


func _ready() -> void:
	body_entered.connect(_on_first_touch, CONNECT_ONE_SHOT)
	body_entered.connect(_close_after_entry, CONNECT_DEFERRED)
	if not body_entered.is_connected(_on_body_entered):
		body_entered.connect(_on_body_entered)


func _on_body_entered(body: Node2D) -> void:
	print(body.name, " entered")


func _close_after_entry(_body: Node2D) -> void:
	shape.disabled = true


func stop_listening() -> void:
	body_entered.disconnect(_on_body_entered)

await

await signal は、シグナルが発火するまで関数を一時停止し、その引数を返します。引数がない場合は null、1 つの引数の場合はその値、2 つ以上の引数の場合は Array を返します。await を含む関数はコルーチンです。その結果を必要とする呼び出し元も await しなければなりません。そうしないと、すぐに続行されます。

extends Node2D

signal door_opened(door_name: String)


func _ready() -> void:
	await get_tree().create_timer(0.5).timeout
	var opened_by: String = await door_opened
	print("Door opened: ", opened_by)
	await play_intro()
	print("Intro finished")


func play_intro() -> void:
	var tween := create_tween()
	tween.tween_property(self, "modulate:a", 1.0, 1.0).from(0.0)
	await tween.finished

await はタイムアウトしません。シグナルが発行されない(またはその発信元が先に解放される)場合、関数はエラーなしでその場で停止します。フォールバックパスが必要な場合は、Timer またはワンショット接続を使用してください。

エディタ接続

ノードドックで作成された接続は、スクリプトではなくシーンファイルに保存されます。

[connection signal="pressed" from="StartButton" to="." method="_on_start_button_pressed"]

メソッドがスクリプトで名前変更または削除された場合でも、接続は .tscn に残ります。Godot 4.7.2 では、接続されたメソッドが存在しないシグナルを発行してもエラーは出力されないため、ボタンは単に動作を停止します。ハンドラの名前を変更した後は、method="old_name" を探してシーンを検索し、更新するか、ノードドックで再接続してください。スクリプトを自己完結させるべき場合はコードで接続し、デザイナーがシーンを配線する場合はエディタで接続してください。同じシグナルとメソッドに対して両方を行うことは避けてください。2 回目の接続は "already connected" とログに記録されます。

呼び下げ、シグナル上げ

ノードはその子ノードのメソッドを呼び出し(所有しており、存在することを認識している)、親や兄弟が反応するためのシグナルを発行します(誰がリスニングしているかを知るべきではありません)。親、または 2 つを構成するノードが接続を行います。

extends Node2D

@onready var player: Node2D = $Player
@onready var health_bar: ProgressBar = $HUD/HealthBar


func _ready() -> void:
	player.connect(&"health_changed", _on_player_health_changed)


func _on_player_health_changed(_old_value: int, new_value: int) -> void:
	health_bar.value = new_value

この親は Player を Node2D としてしか認識しないため、カスタムシグナルを文字列として指定しています。プレイヤースクリプトに class_name Player を付け、変数を Player 型として宣言し、player.health_changed.connect(_on_player_health_changed) と記述することで、パーサーが名前もチェックするようにできます。

多くの無関係なシーンが気にするイベント(プレイヤーの死亡、レベルの終了)については、シグナルのみを宣言する自動読み込みスクリプトをイベントバスとして使用するのが一般的なパターンです:Events.player_died.emit() および Events.player_died.connect(_on_player_died)。

置き換える Godot 3 の形式

Godot 3Godot 4
connect("pressed", self, "_on_pressed")pressed.connect(_on_pressed)
connect("pressed", self, "_on_pressed", [id])pressed.connect(_on_pressed.bind(id))
connect("timeout", self, "_on_timeout", [], CONNECT_ONESHOT)timeout.connect(_on_timeout, CONNECT_ONE_SHOT)
disconnect("pressed", self, "_on_pressed")pressed.disconnect(_on_pressed)
is_connected("pressed", self, "_on_pressed")pressed.is_connected(_on_pressed)
emit_signal("died")died.emit()
yield(obj, "signal_name")await obj.signal_name
funcref(obj, "method")Callable(obj, "method") または obj.method

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

ziva-sh/godot-4-api-pitfalls

Fixes Godot 3 APIs and GDScript syntax that AI assistants write into Godot 4 projects, such as KinematicBody2D, move_and_slide(velocity), export, onready, setget, yield, string connect(), instance(), rand_range, the Tween node, File, change_scene, Spatial, rect_* properties, Pool*Array, OS time functions and the old TileMap API. Use when writing, reviewing or porting GDScript for Godot 4.x, when a script fails with "not declared", "not found in base", "was removed in Godot 4" or "is not present

ziva-sh/godot-control-layout

Builds Godot 4 Control UIs that resize instead of clipping or overlapping - containers versus anchors, anchor presets from code, size flags, custom_minimum_size, MarginContainer margins, Label wrapping, mouse_filter, CanvasLayer HUDs, Godot 4 theme override names (add_theme_color_override and friends) and the display/window/stretch settings for multiple resolutions. Use when creating or fixing menus, HUDs, dialogs and inventory screens, when UI elements are cut off, zero-sized, overlapping, igno

ziva-sh/godot-scene-organization

Structures Godot 4 projects so scenes stay reusable and references do not break - when to make a scene, a script or a Resource, instancing with @export PackedScene, preload and load, @onready and %UniqueName node access, _ready order, groups, autoloads, class_name, and resource UIDs with the .uid files added in Godot 4.4, including how to move or rename files safely. Use when creating new scenes or scripts, deciding how nodes find each other, adding global state or an event bus, moving or renami

ziva-sh/godot-tilemaplayer

Correct Godot 4.3+ TileMapLayer code - set_cell(coords, source_id, atlas_coords), reading cells and custom data, erasing, coordinate conversion, terrains, tile collision through TileSet physics layers, finding the tile a body hit, and migrating from the deprecated TileMap node and its layer-index API. Use when placing, reading or erasing tiles from GDScript, building a TileSet in code, generating levels procedurally, handling tile collisions, or porting TileMap code from Godot 3 or Godot 4.0 to

関連スキル