Godot 4 Signal Kalıpları — Eksiksiz Rehber

1. Giriş — Godot 4'te Neler Değişti

Godot 4, signal'lerin çalışma şeklini tamamen elden geçirdi. Godot 3'ten geliyorsanız: eski string tabanlı object.connect("signal_name", target, "method_name") sözdizimi artık yok. Onun yerine Godot 4, tip güvenli, yeniden düzenlemeye (refactoring) uygun ve hataları çalışma zamanı yerine derleme zamanında yakalayan Callable tabanlı bir API kullanır.

Bu rehber, Godot 4.4+ içinde signal'ler hakkında bilmeniz gereken her şeyi kapsar: tanımlama, bağlama, bağlantı kesme, gönderme, bekleme (await) ve pratikte en kullanışlı kalıplar.

Önemli Nokta

Godot 4'te signal'ler birinci sınıf nesnelerdir. Onlara özellik olarak erişirsiniz (örn. button.pressed) ve üzerlerinde metot çağırırsınız (.connect(), .emit(), .disconnect()). Artık string tabanlı API yok.

2. Özel Signal'ler Tanımlama

Signal'leri betiğinizin başında signal anahtar sözcüğüyle tanımlayın. İsteğe bağlı olarak, dokümantasyon ve editör otomatik tamamlama için parametre adları ve tipleri belirtebilirsiniz.

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)
İpucu

Signal parametrelerine her zaman tip bilgisi ekleyin. Bu, editörde otomatik tamamlamayı etkinleştirir ve kodunuzu kendi kendini belgeler hale getirir. Tip bilgisi olan signal'ler ayrıca Node dock'unun Signals sekmesinde parametre bilgisini gösterir.

3. Signal'leri Bağlama (Yeni Yöntem)

Godot 4'teki en büyük değişiklik, signal'leri nasıl bağladığınızdır. String'ler geçmek yerine, signal'i bir özellik olarak kullanır ve .connect() metodunu bir Callable (bir fonksiyona referans) ile çağırırsınız.

Temel Bağlantı

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() ile Ek Argümanlı Bağlantı

.bind() kullanarak signal ile birlikte ek veri geçirebilirsiniz. Bu, birden fazla signal'i aynı metoda bağlarken kullanışlıdır.

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 (Satır İçi) Bağlantılar

Kısa işleyiciler için doğrudan bir lambda fonksiyonu kullanabilirsiniz. Böylece basit mantık, bağlantı noktasına yakın kalır.

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!")
)
Uyarı

Lambda bağlantıları kolayca kesilemez, çünkü anonim fonksiyona bir referansınız yoktur. Daha sonra bağlantıyı kesmeniz gerekiyorsa, Callable'ı bir değişkende saklayın veya bunun yerine adlandırılmış bir metot kullanın.

Editörde Bağlama (Node Dock)

Signal'leri Godot editör arayüzü üzerinden de bağlayabilirsiniz. Bir node seçin, Node dock > Signals sekmesini açın, bir signal'e çift tıklayın ve hedef node ile metodu seçin. Editör, betiğinizde _on_button_pressed() gibi bir metodu otomatik olarak oluşturur. Bu, kodda .connect() çağırmakla aynıdır — sadece yazma zahmetinden kurtarır.

4. Signal Bağlantısını Kesme

Bir signal'i artık almak istemediğinizde bağlantısını kesin. Bu, node'lar serbest bırakıldığında veya oyun durumları değiştirildiğinde hataları önlemek için önemlidir.

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)
En İyi Uygulama

Sahneler arası signal bağlantıları için (örn. bir Autoload'a bağlanma), node serbest bırakıldığında sarkan referansları önlemek amacıyla her zaman _exit_tree() içinde bağlantıyı kesin:

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. Signal Gönderme

Godot 4'te, eski emit_signal() yerine .emit() kullanın. Signal bir nesnedir, bu yüzden metodu doğrudan onun üzerinde çağırırsınız.

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
Not

Eski emit_signal("signal_name") Godot 4'te teknik olarak hâlâ çalışır ancak kullanımdan kaldırılmıştır. Yeni kod için her zaman signal_name.emit() tercih edin. String tabanlı sürüm, gelecekteki bir Godot sürümünde kaldırılabilir.

6. Signal'leri Bekleme (await)

Godot 4, yield() yerine await getirdi. Bu, bir signal tetiklenene kadar bir fonksiyonu duraklatmanıza olanak tanır — ara sahneler, öğreticiler, sıralı animasyonlar ve zamanlanmış olaylar için mükemmeldir.

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

Beklenen Signal'lerden Değer Almak

Signal argümanlar gönderiyorsa, await bunları döndürür. Tek argüman için değeri doğrudan alırsınız. Birden fazla argüman için bir dizi (array) alırsınız.

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 Bağlantı Bayrakları

Godot, bağlantının davranışını değiştiren bağlantı bayraklarını .connect() metodunun ikinci argümanı olarak sağlar.

CONNECT_ONE_SHOT

Signal bir kez tetiklendikten sonra bağlantı otomatik olarak kaldırılır. Ölüm animasyonları veya başarım açma gibi tek seferlik olaylar için mükemmeldir.

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

Bağlı metot, hemen değil, geçerli karenin sonunda (boşta kalma süresi içinde) çağrılır. Signal işleyicisi sahne ağacını (scene tree) değiştirdiğinde kullanışlıdır; çünkü fizik veya signal işleme sırasında bunu yapmak güvenli değildir.

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

Bayrakları Birleştirme

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

8. Sık Kullanılan Kalıplar

EventBus (Global Signal Merkezi)

EventBus kalıbı, node'ları birbirinden ayırmak için bir Autoload singleton kullanır. Herhangi bir node, başka bir node'a doğrudan referansa ihtiyaç duymadan global olayları gönderebilir veya dinleyebilir. Bu, Godot'taki en güçlü kalıplardan biridir.

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 Kurulumu

Project > Project Settings > Autoload yolunu izleyin, event_bus.gd betiğinizi ekleyin ve adını EventBus koyun. Otomatik olarak global erişilebilir bir singleton haline gelir.

Signal Aktarımı (Ebeveyn-Çocuk İletişimi)

Bir ebeveyn node, çocuklarının signal'lerini dinler ve bilgiyi aktarır veya toplar. Çocukların birbirini bilmesine hiç gerek yoktur.

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

Sıralı Oyun Akışı için 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()

Oluşturulan Node'lar için Dinamik Bağlantılar

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. Geçiş Kılavuzu (Godot 3 → 4)

Godot 3 projenizi taşırken hızlı başvuru için bu tabloyu yer imlerinize ekleyin.

İşlem Godot 3 Godot 4
Bağlama connect("sig", obj, "method") sig.connect(method)
Bağlantı kesme disconnect("sig", obj, "method") sig.disconnect(method)
Gönderme emit_signal("sig", args) sig.emit(args)
Bağlantı kontrolü is_connected("sig", obj, "method") sig.is_connected(method)
Signal bekleme yield(obj, "sig") await obj.sig
Ek argüman bağlama connect("sig", obj, "method", [data]) sig.connect(method.bind(data))
Tek seferlik connect("sig", obj, "method", [], CONNECT_ONESHOT) sig.connect(method, CONNECT_ONE_SHOT)

10. Sık Yapılan Hatalar

1. String Tabanlı connect Kullanmak (Godot 3 Stili)

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() Yerine emit_signal() Kullanmak

emit_signal() hâlâ çalışsa da, derleme zamanı denetimlerini atlar ve resmî olarak kullanımdan kaldırılmıştır. .emit() kullanın.

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. Serbest Bırakılmış Bir Node'a Bağlanmak

Bir signal'i bir node üzerindeki metoda bağlarsanız ve o node queue_free() ile serbest bırakılırsa, sonraki signal gönderimi çökmeye neden olur. Çözümler:

  • _exit_tree() içinde bağlantıyı kesin
  • Tek seferlik olaylar için CONNECT_ONE_SHOT kullanın
  • Göndermeden önce is_instance_valid(target) ile kontrol edin
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. Sahneler Arası Signal'lerin Bağlantısını Kesmeyi Unutmak

Autoload signal'lerine yapılan bağlantılar sahne değişiklikleri boyunca kalıcı olur. _ready() içinde bağlanıp hiç bağlantıyı kesmezseniz, sahne yeniden yüklendiğinde hatalar veya beklenmedik davranışlar alırsınız.

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. Aynı Signal'i İki Kez Bağlamak

_ready() birden fazla kez çağrılırsa (örn. bir node'un ebeveynini değiştirme), aynı metodu yanlışlıkla iki kez bağlayabilirsiniz. Bu durumda işleyici her gönderimde iki kez tetiklenir.

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)

Signal Mimarinizi Yapay Zeka Yönetsin İster misiniz?

Godot MCP Pro, Claude gibi yapay zeka asistanlarını doğrudan Godot editörünüze bağlar. Projenizin tamamındaki signal akışlarını otomatik olarak bağlayabilir, kesebilir, denetleyebilir ve görselleştirebilir.

analyze_signal_flow find_signal_connections connect_signal disconnect_signal get_signals
Godot MCP Pro'yu Edinin — $15