Godot 4 Signal Patterns — संपूर्ण गाइड

1. परिचय — Godot 4 में क्या बदला

Godot 4 ने signals के काम करने के तरीके को पूरी तरह से नया रूप दिया है। अगर आप Godot 3 से आ रहे हैं, तो पुरानी string-आधारित सिंटैक्स object.connect("signal_name", target, "method_name") अब मौजूद नहीं है। इसकी जगह Godot 4 एक callable-आधारित API का उपयोग करता है जो type-safe और refactoring-अनुकूल है और errors को runtime के बजाय compile time पर पकड़ लेता है।

यह गाइड वह सब कुछ कवर करती है जो आपको Godot 4.4+ में signals के बारे में जानना चाहिए: घोषित करना, connect करना, disconnect करना, emit करना, await करना और वास्तविक दुनिया के सबसे उपयोगी patterns।

मुख्य बात

Godot 4 में signals first-class objects हैं। आप इन्हें properties के रूप में एक्सेस करते हैं (जैसे, button.pressed) और इन पर methods कॉल करते हैं (.connect(), .emit(), .disconnect())। अब कोई string-आधारित API नहीं।

2. कस्टम signals घोषित करना

अपनी स्क्रिप्ट के शीर्ष पर signal कीवर्ड के साथ signals घोषित करें। आप वैकल्पिक रूप से documentation और editor autocomplete के लिए parameter नाम और types निर्दिष्ट कर सकते हैं।

player.gd
# 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)
टिप

signal parameters में हमेशा type hints जोड़ें। इससे editor में autocomplete सक्रिय होता है और आपका कोड स्वयं-दस्तावेज़ीकृत बनता है। type hints वाले signals, Node dock के Signals tab में parameter जानकारी भी दिखाते हैं।

3. Signals को connect करना (नया तरीका)

Godot 4 में सबसे बड़ा बदलाव यह है कि आप signals को कैसे connect करते हैं। strings पास करने के बजाय, आप signal को एक property के रूप में उपयोग करते हैं और .connect() को एक Callable (किसी function का reference) के साथ कॉल करते हैं।

बुनियादी connection

GDScript
# 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!")

bind() के माध्यम से अतिरिक्त arguments के साथ connection

signal के साथ अतिरिक्त data पास करने के लिए .bind() का उपयोग करें। यह तब उपयोगी है जब आप कई signals को एक ही method से connect करते हैं।

GDScript
# 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)

Lambda (inline) connections

छोटे handlers के लिए, आप सीधे एक lambda function का उपयोग कर सकते हैं। इससे सरल logic connection बिंदु के पास रहती है।

GDScript
# 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!")
)
चेतावनी

Lambda connections को आसानी से disconnect नहीं किया जा सकता क्योंकि आपके पास anonymous function का reference नहीं होता। अगर आपको बाद में disconnect करना है, तो Callable को एक variable में स्टोर करें या इसके बजाय named method का उपयोग करें।

Editor में connect करना (Node dock)

आप अभी भी Godot editor UI के माध्यम से signals connect कर सकते हैं। एक node चुनें, Node dock > Signals tab खोलें, किसी signal पर डबल-क्लिक करें, और target node तथा method चुनें। editor आपकी स्क्रिप्ट में स्वतः _on_button_pressed() जैसी method बना देगा। यह कोड में .connect() कॉल करने के समान ही है — बस टाइपिंग बचती है।

4. Signals को disconnect करना

जब आप किसी signal को प्राप्त नहीं करना चाहते तो उसे disconnect करें। यह nodes के free होने या game states बदलने पर errors से बचने के लिए महत्वपूर्ण है।

GDScript
# 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)
बेस्ट प्रैक्टिस

scene-पार signal connections (जैसे किसी Autoload से connect करना) के लिए, node के free होने पर dangling references रोकने के लिए हमेशा _exit_tree() में disconnect करें:

GDScript
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. Signals को emit करना

Godot 4 में, पुराने emit_signal() के बजाय .emit() का उपयोग करें। signal एक object है, इसलिए आप method को सीधे उस पर कॉल करते हैं।

player.gd
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
नोट

पुराना emit_signal("signal_name") Godot 4 में तकनीकी रूप से अभी भी काम करता है लेकिन deprecated है। नए कोड के लिए हमेशा signal_name.emit() को प्राथमिकता दें। string-आधारित संस्करण भविष्य के किसी Godot रिलीज़ में हटाया जा सकता है।

6. Signals का await करना

Godot 4 ने yield() की जगह await ले लिया है। इससे आप किसी function को तब तक रोक सकते हैं जब तक कोई signal fire न हो — जो cutscenes, tutorials, अनुक्रमिक animations और timed events के लिए एकदम सही है।

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

await किए गए signals से values प्राप्त करना

अगर signal arguments emit करता है, तो await उन्हें लौटाता है। एक single argument के लिए, आपको value सीधे मिलती है। कई arguments के लिए, आपको एक array मिलता है।

GDScript
# 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. Signal connection flags

Godot .connect() के दूसरे argument के रूप में connection flags प्रदान करता है, जिनसे आप connection के व्यवहार को समायोजित कर सकते हैं।

CONNECT_ONE_SHOT

signal के एक बार fire होने के बाद connection स्वतः हटा दिया जाता है। death animations या achievement unlocks जैसी एकबारगी events के लिए एकदम सही।

GDScript
# 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

connected method तुरंत के बजाय वर्तमान frame के अंत में (idle समय के दौरान) कॉल की जाती है। यह तब उपयोगी है जब signal handler scene tree को बदलता है, जो physics या signal processing के दौरान सुरक्षित नहीं होता।

GDScript
# 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()

Flags को जोड़ना

GDScript
# One-shot AND deferred
trigger.body_entered.connect(_on_trigger, CONNECT_ONE_SHOT | CONNECT_DEFERRED)

8. आम patterns

EventBus (ग्लोबल signal hub)

EventBus pattern nodes को decouple करने के लिए एक Autoload singleton का उपयोग करता है। कोई भी node दूसरे node के सीधे reference की आवश्यकता के बिना global events emit या सुन सकता है। यह Godot में सबसे शक्तिशाली patterns में से एक है।

event_bus.gd (Autoload)
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
player.gd (emitter)
func die() -> void:
    # Any script can emit global signals
    EventBus.player_died.emit()
hud.gd (listener)
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()
Autoload सेट अप करना

Project > Project Settings > Autoload पर जाएँ, अपनी event_bus.gd स्क्रिप्ट जोड़ें और उसे EventBus नाम दें। यह स्वतः एक globally accessible singleton बन जाता है।

Signal relay (parent-child संचार)

एक parent node अपने children के signals को सुनता है और जानकारी को relay या aggregate करता है। children को कभी एक-दूसरे के बारे में जानने की जरूरत नहीं होती।

inventory.gd
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()

अनुक्रमिक game flow के लिए Signal + Await

level_manager.gd
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()

spawn किए गए nodes के लिए डायनामिक connections

enemy_spawner.gd
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. माइग्रेशन चीट शीट (Godot 3 → 4)

अपने Godot 3 प्रोजेक्ट को पोर्ट करते समय त्वरित संदर्भ के लिए इस तालिका को बुकमार्क करें।

ऑपरेशन Godot 3 Godot 4
Connect connect("sig", obj, "method") sig.connect(method)
Disconnect disconnect("sig", obj, "method") sig.disconnect(method)
Emit emit_signal("sig", args) sig.emit(args)
Connection जाँचना is_connected("sig", obj, "method") sig.is_connected(method)
Signal का इंतजार करना yield(obj, "sig") await obj.sig
अतिरिक्त args bind करना 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. आम गलतियाँ

1. String-आधारित connect (Godot 3 शैली) का उपयोग करना

GDScript
# 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. .emit() के बजाय emit_signal() का उपयोग करना

हालाँकि emit_signal() अभी भी काम करता है, यह compile-time जाँचों को दरकिनार करता है और आधिकारिक रूप से deprecated है। .emit() का उपयोग करें।

GDScript
# AVOID — deprecated, no compile-time checks
emit_signal("health_changed", health)

# PREFER — type-safe, catches typos at compile time
health_changed.emit(health)

3. किसी free किए गए node से connect करना

अगर आप किसी signal को किसी node की method से connect करते हैं, और वह node queue_free() हो जाता है, तो अगली signal emission crash हो जाएगी। समाधान:

  • _exit_tree() में disconnect करें
  • एकबारगी events के लिए CONNECT_ONE_SHOT का उपयोग करें
  • emit करने से पहले is_instance_valid(target) से जाँचें
GDScript
# 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. scene-पार signals को disconnect करना भूल जाना

Autoload signals से connections scene बदलावों के आर-पार बने रहते हैं। अगर आप _ready() में connect करते हैं लेकिन कभी disconnect नहीं करते, तो scene के reload होने पर आपको errors या अप्रत्याशित व्यवहार मिलेगा।

GDScript
# 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. एक ही signal को दो बार connect करना

अगर _ready() कई बार कॉल होता है (जैसे किसी node को re-parent करना), तो आप गलती से एक ही method को दो बार connect कर सकते हैं। तब handler प्रति emission दो बार fire होगा।

GDScript
# Guard against double-connection
func _ready() -> void:
    if not EventBus.score_changed.is_connected(_on_score_changed):
        EventBus.score_changed.connect(_on_score_changed)

क्या आप चाहते हैं कि AI आपके signal architecture को संभाले?

Godot MCP Pro, Claude जैसे AI assistants को सीधे आपके Godot editor से जोड़ता है। यह आपके पूरे प्रोजेक्ट में signal flows को connect, disconnect, audit और visualize कर सकता है — स्वचालित रूप से।

analyze_signal_flow find_signal_connections connect_signal disconnect_signal get_signals
Godot MCP Pro पाएँ — $15