CommunityCodierung & Entwicklunggithub.com

ziva-sh/godot-signals

Godot 4 Signal-Patterns und ihre Fehlermodi – deklarieren typisierter Signale, emit(), connect() und disconnect() mit Callables, bind() und unbind(), Lambdas, CONNECT_ONE_SHOT und CONNECT_DEFERRED, await auf Signale und Timer, Editor-Verbindungen in .tscn-Dateien und die Call-Down-Signal-Up-Regel.

Was ist godot-signals?

Dieses Skill beschreibt umfassend das Signalsystem in Godot 4 und hebt die Unterschiede zu Godot 3 hervor. Es zeigt, wie man typisierte Signale deklariert, mit emit() auslöst und über connect() mit Callables verbindet – einschließlich der Verwendung von bind(), unbind() und Lambdas. Wichtige Fehlermodi wie doppelte Verbindungen, das Problem mit nicht existierenden Methoden bei Editor-Verbindungen und die Verwendung von CONNECT_ONE_SHOT sowie CONNECT_DEFERRED werden erklärt. Das Skill behandelt auch die asynchrone Programmierung mit await, die Call-Down-Signal-Up-Architektur und bietet eine Referenztabelle zur Migration von Godot-3-Code. Es unterstützt die Godot 4 Engine und ist besonders nützlich für die Verdrahtung von UI-Buttons, Timern, Area2D/Body-Events und benutzerdefinierten Spielereignissen sowie für die Fehlersuche bei Verbindungsproblemen.

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

Installed? Explore more Codierung & Entwicklung skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Signale in Godot 4

In Godot 4 ist ein Signal ein erstklassiger Signal-Wert und ein Methodenverweis ein Callable. Verwenden Sie überall die Objektsyntax (button.pressed.connect(_on_pressed)). Der Parser erkennt dann einen falsch geschriebenen Handler und ein falsch geschriebenes Signal auf self; ein falsch geschriebenes Signal auf einem anderen typisierten Knoten wird abgefangen, wenn unsafe_property_access auf Error gesetzt ist (siehe Skill godot-4-api-pitfalls). Die String-Formen (connect("pressed", ...), emit_signal("died")) werden nur zur Laufzeit geprüft.

Deklarieren, emitten, verbinden

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")

Der Handler muss exakt die Argumente akzeptieren, die das Signal ausgibt. Ein Missmatch ist kein Parse-Fehler; zum Zeitpunkt des Emittens protokolliert Godot Error calling from signal 'x' to callable: '...': Method expected 0 argument(s), but called with 1. und überspringt den Handler.

bind() und unbind()

  • bind(a, b) hängt zusätzliche Argumente nach den eigenen Argumenten des Signals an. Ein Handler für pressed, der mit einem Wert gebunden wird, nimmt einen Parameter entgegen; für health_changed(old, new), der mit einem Wert gebunden wird, nimmt er drei Parameter entgegen, in der Reihenfolge old, new, bound.
  • unbind(n) entfernt die letzten n Signal-Argumente, sodass eine parameterlose Funktion ein Signal verarbeiten kann, das einige sendet.
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

Trennen, Duplikate und Einmalverbindungen

  • disconnect() benötigt einen Callable, der mit dem verbundenen übereinstimmt. _handler.bind(1), erneut erstellt, ist gleichwertig und funktioniert. Ein Lambda tut das nicht: bewahren Sie es in einer Variable auf und trennen Sie diese Variable.
  • Das zweimalige Verbinden desselben Callable protokolliert Signal 'x' is already connected to given callable ... und behält eine Verbindung. Schützen Sie sich mit is_connected(), wenn Code zweimal ausgeführt werden kann, z. B. in _ready() eines Knotens, der dem Baum erneut hinzugefügt wird.
  • connect(callable, CONNECT_ONE_SHOT) trennt die Verbindung nach der ersten Emission. CONNECT_DEFERRED führt den Handler zur Leerlaufzeit aus. Verwenden Sie es (oder set_deferred()), wenn ein Physik-Callback wie body_entered den Physikzustand ändert; dies direkt zu tun, protokolliert Can't change this state while flushing queries.
  • Verbindungen zu einem Objekt werden entfernt, wenn dieses Objekt freigegeben wird.
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 pausiert die Funktion, bis das Signal ausgelöst wird, und gibt seine Argumente zurück: null für keine Argumente, den Wert für eines, ein Array für zwei oder mehr. Eine Funktion, die await enthält, ist eine Koroutine; Aufrufer, die ihr Ergebnis benötigen, müssen ebenfalls await darauf warten, sonst fahren sie sofort fort.

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 timeout nie. Wenn das Signal niemals ausgelöst wird (oder sein Emitter zuerst freigegeben wird), stoppt die Funktion einfach dort, ohne Fehler. Verwenden Sie einen Timer oder eine Einmalverbindung, wenn ein Fallback-Pfad benötigt wird.

Editor-Verbindungen

Im Knoten-Dock erstellte Verbindungen werden in der Szenendatei gespeichert, nicht im Skript:

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

Wenn die Methode im Skript umbenannt oder gelöscht wird, bleibt die Verbindung im .tscn. In Godot 4.7.2 gibt das Emitten eines Signals, dessen verbundene Methode nicht existiert, keinen Fehler aus, sodass der Button einfach nicht mehr funktioniert. Suchen Sie nach dem Umbenennen eines Handlers in den Szenen nach method="old_name" und aktualisieren Sie sie, oder verbinden Sie sie im Knoten-Dock neu. Verbinden Sie im Code, wenn das Skript in sich abgeschlossen sein soll; verbinden Sie im Editor, wenn Designer Szenen verdrahten. Vermeiden Sie beides für dasselbe Signal und dieselbe Methode: das zweite Verbinden protokolliert "already connected".

Call Down, Signal Up

Ein Knoten ruft Methoden auf seinen Kindern auf (er besitzt sie und weiß, dass sie existieren) und emittiert Signale, auf die sein Elternteil oder Geschwisterknoten reagieren können (er sollte nicht wissen, wer zuhört). Der Elternteil oder der Knoten, der die beiden zusammensetzt, führt die Verbindung durch:

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

Dieser Elternteil kennt Player nur als Node2D, daher benennt er das benutzerdefinierte Signal als String. Geben Sie dem Player-Skript einen class_name Player, typisieren Sie die Variable als Player und schreiben Sie player.health_changed.connect(_on_player_health_changed), damit der Parser auch den Namen prüft.

Für Ereignisse, die viele nicht verwandte Szenen betreffen (Spieler gestorben, Level beendet), ist ein häufiges Muster ein Autoload-Skript, das nur Signale deklariert und als Ereignisbus dient: Events.player_died.emit() und Events.player_died.connect(_on_player_died).

Zu ersetzende Godot-3-Formen

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") oder 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

Verwandte Skills