1. Introduzione — Cosa è cambiato in Godot 4
Godot 4 ha rivoluzionato completamente il funzionamento dei segnali. Se arrivi da Godot 3: la vecchia sintassi basata su stringhe object.connect("signal_name", target, "method_name") non esiste più. Al suo posto c'è un'API basata su Callable, type-safe e adatta al refactoring, che intercetta gli errori a tempo di compilazione anziché a runtime.
Questa guida copre tutto ciò che devi sapere sui segnali in Godot 4.4+: dichiarazione, collegamento, scollegamento, emissione, await e i pattern più utili nella pratica.
In Godot 4 i segnali sono oggetti di prima classe. Vi accedi come proprietà (ad es. button.pressed) e chiami metodi su di essi (.connect(), .emit(), .disconnect()). Niente più API basata su stringhe.
2. Dichiarare segnali personalizzati
Dichiara i segnali all'inizio dello script con la parola chiave signal. Facoltativamente puoi specificare nomi e tipi dei parametri, per la documentazione e il completamento automatico nell'editor.
# Simple signal with no parameters
signal game_over
# Signal with typed parameters
signal health_changed(new_health: int)
# Signal with multiple parameters
signal item_picked_up(item_name: String, quantity: int)
# Signal with no type hints (works, but typed is recommended)
signal something_happened(data)
Aggiungi sempre le annotazioni di tipo ai parametri dei segnali. Così attivi il completamento automatico nell'editor e rendi il codice auto-documentante. I segnali con annotazioni di tipo mostrano anche le informazioni sui parametri nella scheda Signals del pannello Node.
3. Collegare i segnali (il nuovo metodo)
Il cambiamento più grande in Godot 4 è il modo in cui colleghi i segnali. Invece di passare stringhe, usi il segnale come proprietà e chiami .connect() con un Callable (un riferimento a una funzione).
Collegamento di base
# Godot 3 (OLD — no longer works in Godot 4)
# button.connect("pressed", self, "_on_button_pressed")
# Godot 4 — callable-based connection
button.pressed.connect(_on_button_pressed)
func _on_button_pressed() -> void:
print("Button was pressed!")
Collegamento con argomenti aggiuntivi tramite bind()
Usa .bind() per passare dati aggiuntivi insieme al segnale. È utile quando colleghi più segnali allo stesso metodo.
# Pass extra data via bind()
buy_button.pressed.connect(_on_item_button.bind("sword"))
sell_button.pressed.connect(_on_item_button.bind("shield"))
func _on_item_button(item_id: String) -> void:
print("Selected item: ", item_id)
Collegamenti con lambda (inline)
Per gli handler brevi puoi usare direttamente una funzione lambda. In questo modo la logica semplice resta vicina al punto di collegamento.
# Lambda — great for one-liners
button.pressed.connect(func(): print("Button pressed!"))
# Lambda with parameters
health_changed.connect(func(hp: int): health_label.text = str(hp))
# Multi-line lambda
enemy.died.connect(func():
score += 100
score_label.text = "Score: %d" % score
print("Enemy defeated!")
)
I collegamenti con lambda non si scollegano facilmente, perché non hai un riferimento alla funzione anonima. Se in seguito devi scollegare, salva il Callable in una variabile oppure usa un metodo con nome.
Collegare nell'editor (pannello Node)
Puoi comunque collegare i segnali tramite l'interfaccia dell'editor di Godot. Seleziona un nodo, apri la scheda Node dock > Signals, fai doppio clic su un segnale e scegli nodo e metodo di destinazione. L'editor genera automaticamente un metodo come _on_button_pressed() nel tuo script. È identico a chiamare .connect() nel codice — ti fa solo risparmiare digitazione.
4. Scollegare i segnali
Scollega un segnale quando non vuoi più riceverlo. È importante per evitare errori quando i nodi vengono liberati o quando cambia lo stato di gioco.
# Disconnect a signal
button.pressed.disconnect(_on_button_pressed)
# Always check before disconnecting to avoid errors
if button.pressed.is_connected(_on_button_pressed):
button.pressed.disconnect(_on_button_pressed)
Per i collegamenti di segnali tra scene diverse (ad es. verso un Autoload), scollega sempre in _exit_tree() per evitare riferimenti pendenti quando il nodo viene liberato:
func _ready() -> void:
EventBus.player_died.connect(_on_player_died)
func _exit_tree() -> void:
if EventBus.player_died.is_connected(_on_player_died):
EventBus.player_died.disconnect(_on_player_died)
5. Emettere i segnali
In Godot 4 usi .emit() al posto del vecchio emit_signal(). Il segnale è un oggetto, quindi chiami il metodo direttamente su di esso.
signal health_changed(new_health: int)
signal died
var health: int = 100
func take_damage(amount: int) -> void:
health -= amount
health_changed.emit(health) # Emit with argument
if health <= 0:
died.emit() # Emit with no arguments
Il vecchio emit_signal("signal_name") tecnicamente funziona ancora in Godot 4, ma è deprecato. Per il nuovo codice preferisci sempre signal_name.emit(). La variante basata su stringhe potrebbe essere rimossa in una futura release di Godot.
6. Attendere i segnali (await)
Godot 4 ha sostituito yield() con await. Ti permette di mettere in pausa una funzione finché un segnale non si attiva — perfetto per cutscene, tutorial, animazioni sequenziali ed eventi temporizzati.
func play_cutscene() -> void:
# Wait for a timer
await get_tree().create_timer(2.0).timeout
# Wait for an animation to finish
animation_player.play("intro")
await animation_player.animation_finished
# Wait for player input (custom signal)
dialogue_label.text = "Press any key to continue..."
await player_pressed_continue
# Continue execution after the signal fires
print("Cutscene complete!")
Ottenere valori dai segnali attesi con await
Se il segnale emette argomenti, await li restituisce. Con un singolo argomento ottieni il valore direttamente. Con più argomenti ottieni un array.
# Single parameter — returns the value directly
var final_health: int = await health_changed
print("Health is now: ", final_health)
# Multiple parameters — returns an array
var result = await item_picked_up
var item_name: String = result[0]
var quantity: int = result[1]
7. Flag di connessione dei segnali
Godot offre i flag di connessione come secondo argomento di .connect(), con cui puoi modificare il comportamento della connessione.
CONNECT_ONE_SHOT
La connessione viene rimossa automaticamente dopo che il segnale si è attivato una volta. Perfetto per eventi una tantum come animazioni di morte o sblocchi di obiettivi.
# Auto-disconnects after firing once
enemy.died.connect(_on_first_kill, CONNECT_ONE_SHOT)
func _on_first_kill() -> void:
unlock_achievement("first_blood")
CONNECT_DEFERRED
Il metodo collegato viene chiamato alla fine del frame corrente (durante il tempo di idle) anziché immediatamente. Utile quando l'handler del segnale modifica lo scene tree, operazione non sicura durante l'elaborazione della fisica o dei segnali.
# Called at end of frame — safe for scene tree changes
button.pressed.connect(_on_restart, CONNECT_DEFERRED)
func _on_restart() -> void:
get_tree().reload_current_scene()
Combinare i flag
# One-shot AND deferred
trigger.body_entered.connect(_on_trigger, CONNECT_ONE_SHOT | CONNECT_DEFERRED)
8. Pattern comuni
EventBus (hub globale di segnali)
Il pattern EventBus usa un singleton Autoload per disaccoppiare i nodi. Qualsiasi nodo può emettere o ascoltare eventi globali senza bisogno di un riferimento diretto a un altro nodo. È uno dei pattern più potenti di Godot.
extends Node
# Define all global signals in one place
signal player_died
signal score_changed(new_score: int)
signal level_completed(level_id: int)
signal item_collected(item_name: String)
signal settings_changed
func die() -> void:
# Any script can emit global signals
EventBus.player_died.emit()
func _ready() -> void:
# Any script can listen to global signals
EventBus.score_changed.connect(_on_score_changed)
EventBus.player_died.connect(_on_player_died)
func _on_score_changed(new_score: int) -> void:
score_label.text = "Score: %d" % new_score
func _on_player_died() -> void:
game_over_screen.show()
Vai su Progetto > Impostazioni progetto > Autoload, aggiungi il tuo script event_bus.gd e chiamalo EventBus. Diventa automaticamente un singleton accessibile globalmente.
Relay di segnali (comunicazione genitore-figlio)
Un nodo genitore ascolta i segnali dei suoi figli e inoltra o aggrega le informazioni. I figli non devono mai conoscersi tra loro.
signal inventory_updated
func _ready() -> void:
# Connect to all slot children
for slot in get_children():
if slot.has_signal("item_changed"):
slot.item_changed.connect(_on_slot_changed)
func _on_slot_changed() -> void:
inventory_updated.emit()
Signal + Await per un flusso di gioco sequenziale
func run_level() -> void:
spawn_enemies()
await EventBus.all_enemies_defeated
show_treasure_chest()
await EventBus.chest_opened
play_exit_animation()
await get_tree().create_timer(1.5).timeout
load_next_level()
Collegamenti dinamici per nodi generati (spawn)
func spawn_enemy(pos: Vector2) -> void:
var enemy = enemy_scene.instantiate()
enemy.position = pos
# Connect signals before adding to scene tree
enemy.died.connect(_on_enemy_died.bind(enemy))
enemy.health_changed.connect(_on_enemy_health_changed)
add_child(enemy)
func _on_enemy_died(enemy: Node) -> void:
enemies_alive -= 1
enemy.queue_free()
9. Cheat sheet di migrazione (Godot 3 → 4)
Aggiungi questa tabella ai preferiti come riferimento rapido quando porti il tuo progetto Godot 3.
| Operazione | Godot 3 | Godot 4 |
|---|---|---|
| Collegare | connect("sig", obj, "method") |
sig.connect(method) |
| Scollegare | disconnect("sig", obj, "method") |
sig.disconnect(method) |
| Emettere | emit_signal("sig", args) |
sig.emit(args) |
| Verificare la connessione | is_connected("sig", obj, "method") |
sig.is_connected(method) |
| Attendere un segnale | yield(obj, "sig") |
await obj.sig |
| Associare argomenti aggiuntivi | connect("sig", obj, "method", [data]) |
sig.connect(method.bind(data)) |
| One-shot | connect("sig", obj, "method", [], CONNECT_ONESHOT) |
sig.connect(method, CONNECT_ONE_SHOT) |
10. Errori comuni
1. Usare il connect basato su stringhe (stile Godot 3)
# WRONG — Godot 3 syntax, will not compile
button.connect("pressed", self, "_on_button_pressed")
# CORRECT — Godot 4 syntax
button.pressed.connect(_on_button_pressed)
2. Usare emit_signal() invece di .emit()
Anche se emit_signal() funziona ancora, aggira i controlli a tempo di compilazione ed è ufficialmente deprecato. Usa .emit().
# AVOID — deprecated, no compile-time checks
emit_signal("health_changed", health)
# PREFER — type-safe, catches typos at compile time
health_changed.emit(health)
3. Collegarsi a un nodo liberato
Se colleghi un segnale a un metodo su un nodo e quel nodo viene liberato con queue_free(), la successiva emissione del segnale provocherà un crash. Soluzioni:
- Scollegare in
_exit_tree() - Usare
CONNECT_ONE_SHOTper gli eventi una tantum - Verificare con
is_instance_valid(target)prima di emettere
# Safe emission pattern
for connection in my_signal.get_connections():
if is_instance_valid(connection["callable"].get_object()):
pass # Connection is still valid
my_signal.emit() # Godot handles invalid connections gracefully in 4.x
4. Dimenticare di scollegare i segnali tra scene
I collegamenti ai segnali di un Autoload persistono tra i cambi di scena. Se colleghi in _ready() ma non scolleghi mai, otterrai errori o comportamenti imprevisti quando la scena viene ricaricata.
# WRONG — never disconnects, leaks across scene changes
func _ready() -> void:
EventBus.score_changed.connect(_on_score_changed)
# CORRECT — clean disconnect
func _ready() -> void:
EventBus.score_changed.connect(_on_score_changed)
func _exit_tree() -> void:
EventBus.score_changed.disconnect(_on_score_changed)
5. Collegare lo stesso segnale due volte
Se _ready() viene chiamato più volte (ad es. riassegnando il genitore di un nodo), potresti collegare per errore lo stesso metodo due volte. L'handler verrà quindi eseguito due volte a ogni emissione.
# Guard against double-connection
func _ready() -> void:
if not EventBus.score_changed.is_connected(_on_score_changed):
EventBus.score_changed.connect(_on_score_changed)
Vuoi che l'IA gestisca l'architettura dei tuoi segnali?
Godot MCP Pro collega assistenti IA come Claude direttamente al tuo editor Godot. Può collegare, scollegare, analizzare e visualizzare i flussi di segnali nell'intero progetto — automaticamente.
analyze_signal_flow
find_signal_connections
connect_signal
disconnect_signal
get_signals