Godot Engine Eğitim Serisi - Bölüm 11: Ses, Müzik, UI (Kullanıcı Arayüzü), Animasyon
Godot 3D oyununa ses, müzik, UI ve AnimationPlayer ile animasyon ekleme. Autoload (Singleton) ile kesintisiz müzik sistemi. Türkçe.
3D oyun projemizin (“Squash the Creeps!”) temel mekaniklerini başarıyla kurduk. Zıplayabiliyor, düşmanları ezebiliyoruz ancak ölmüyoruz ve oyunumuz şu an sessiz, skorsuz ve biraz cansız görünüyor.
Bu final bölümünde; oyuncumuzun ölmesini sağlayacak, oyunumuza bir UI (Kullanıcı Arayüzü) giydirecek, sahne geçişlerinde kesilmeyen bir müzik sistemi (Autoload) kuracak ve son olarak AnimationPlayer ile 3D nesnelerimize hayat vereceğiz.
Oyuncunun Ölmesi ve Hitbox
Düşmanın üstüne basarsak onu eziyoruz, peki ya düşman bize yandan çarparsa? Bunu algılamak için oyuncuya bir Hitbox (Çarpışma Kutusu) eklemeliyiz.
player.tscnsahnesini açın ve kökPlayernode’una birArea3Dçocuğu ekleyip adınıMobDetectoryapın.MobDetector‘a birCollisionShape3Dçocuğu ekleyin ve şekliniCylinderShape3Dolarak ayarlayın.Silindirin boyutlarını oyuncu küresinden biraz daha geniş yapın ve üst kısma doğru konumlandırın. Böylece oyuncu zıpladığında silindir yukarıda kalır ve alttan geçen düşmanlar yanlışlıkla çarpışma tetiklemez.
MobDetector‘ın özelliklerinden Monitorable ayarını kapatın, Monitoring ayarını açık bırakın. Collision Mask olarak sadeceenemieskatmanını seçin.
Sinyali Bağlamak ve Oyuncuyu Silmek
MobDetectorseçiliyken Signals sekmesindenbody_enteredsinyalini Player scriptinize bağlayın.player.gddosyanızın en üstüne birhitsinyali tanımlayın:
1
signal hit
Kodun Satır Satır Açıklaması:
signal hit: Tıpkı düşmanın ezildiğinde yaydığı sinyal gibi, bu sefer biz oyuncu için kendimiz yepyeni bir “hit” (hasar aldım / vuruldum / öldüm) sinyali tanımlıyoruz.
- Scriptin en altına da şu fonksiyonları ekleyin:
1
2
3
4
5
6
func _on_mob_detector_body_entered(body):
die()
func die():
hit.emit()
queue_free()
Kodun Satır Satır Açıklaması:
func _on_mob_detector_body_entered(body):: Oyuncunun gölgesine bir Area3D (tehlike algılayıcı sensör) eklemiştik. Bu fonksiyon, o sensöre yabancı bir fiziksel cisim (body) değdiği an (entered) tetiklenir. Çarpan şey düşmandır (çünkü maskesinden sadece düşmanları dinlemesini söylemiştik, yeri veya havayı görmezden gelir).die(): Eğer sensöre biri değdiyse aşağıya yazdığımız kendidie(ölüm) fonksiyonumuzu çalıştır.func die():: Oyuncu öldüğünde olmasını istediğimiz şeyleri yazdığımız blok.hit.emit(): Yukarıda oluşturduğumuzhitsinyalini yakar. “Yardım edin, vuruldum!” diye bağırır. Bunu yapıyoruz ki ana oyun döngüsündeki (Main) müzik dursun, ekranda Game Over yazsın.queue_free(): Kendimizi oyun sahnesinden tamamen sileriz. Karakter yok olur.
- Son dokunuş olarak
main.tscnana sahnenizi açın,Playerinstance’ınızı seçip yeni oluşturduğunuzhitsinyalini Main scriptinize bağlayın. Oyun bittiğinde düşman akışını kesmek için fonksiyonun içini şöyle doldurun:
1
2
func _on_player_hit():
$MobTimer.stop()
Kodun Satır Satır Açıklaması:
func _on_player_hit():: (Bu kodMainana sayfasındadır). Oyuncu vuruluphitsinyalini yayınladığında otomatik tetiklenmesi için bağladığımız özel durumdur.$MobTimer.stop(): Oyuncu öldüğüne göre artık yeni düşman yağdırmanın anlamı yok, dolayısıyla o fırını durdur ki ekrana akın etmeyi kessinler.
3D Oyuna UI (Kullanıcı Arayüzü) Giydirmek
Godot’da 2D veya 3D oyun yapıyor olmanız fark etmez; UI elemanları her zaman Control node’ları kullanılarak 2D düzlemde çizilir.
main.tscnsahnenizi açın. Main node’una birControlçocuğu ekleyin ve adınıUserInterfaceyapın.İşlemleri kolayca yapabilmek için editörün üstünden 2D çalışma alanına geçin.
UserInterfacenode’una birLabelçocuğu ekleyip adınıScoreLabelyapın ve metin (Text) olarakScore: 0yazın.
ScoreLabel metni “Score: 0” olarak ayarlandı
- 3D dünyamızın arka planı parlak olduğu için beyaz yazı okunmayacaktır. Inspector’dan Theme Overrides > Colors altından Font Color’ı siyah yapın.
Font Color siyah yapıldı — beyaz 3D sahnede okunabilir
- Oyuncu öldüğünde çıkacak “Yeniden Oyna” ekranı için
UserInterfacenode’una birColorRectekleyip adınıRetryyapın. Tüm ekranı kaplaması için Anchor ayarlarından Full Rect seçin ve rengini koyu/yarı saydam siyah yapın.
Full Rect ile node tüm viewport’u kaplar
Koyu, yarı saydam renk — arka planı kararttır
- Bunun altına da bir
LabelekleyipPress Enter to retry.yazın ve ekrana ortalayın.
Skoru ve Yeniden Oynamayı Koda Dökmek
ScoreLabel node’una bir script ekleyin. Düşmanların squashed sinyalini bu scripte bağlayarak skoru güncelleyeceğiz:
1
2
3
4
5
6
extends Label
var score = 0
func _on_mob_squashed():
score += 1
text = "Score: %s" % score
Kodun Satır Satır Açıklaması:
extends Label: Bu kodun, ekranda yazı göstermeye yarayan bir “Label” (Etiket) düğümüne ait olduğunu belirtir. Arayüzümüze eklediğimizScoreLabel‘dir.var score = 0: Oyun ilk başladığında oyuncunun puanını tutacağımız değişkeni yaratır ve0yaparız.func _on_mob_squashed():: Düşmanlar ezildiğinde yaydıklarısquashedsinyalinin yakalandığı fonksiyondur. Okyanustaki herhangi bir düşman “Ben ezildim!” diye bağırdığında bu etiket onu duyar.score += 1: Düşman ezildiğini duyduğumuza göre, skoru1artırırız.text = "Score: %s" % score: Etiketin ekranda görünen yazısını (text) güncelleriz.%skısmı bir yer tutucudur. Cümlenin sonundaki% scoreifadesi ile, bu yer tutucunun yerine güncel skorumuzu yazarız. Böylece ekranda “Score: 1”, “Score: 2” şeklinde sürekli güncellenen bir yazı görürüz.
main.gd scriptinizi de güncelleyerek oyun bitişi ve yeniden başlama mantığını kurmalısınız. Oyuncu öldüğünde $UserInterface/Retry.show() ile karartma ekranını gösterebilirsiniz. Yeniden başlamak için _unhandled_input() fonksiyonu içinde oyuncunun Enter tuşuna basmasını dinleyip, get_tree().reload_current_scene() komutuyla sahneyi sıfırdan yükleyebilirsiniz.
Kesintisiz Müzik İçin Autoload (Singleton) Kullanımı
Eğer müziği doğrudan Main sahnesine eklerseniz, oyuncu her öldüğünde ve sahne reload_current_scene() ile yenilendiğinde müzik de başa döner. Müziğin arka planda sürekli çalması için Autoload (Singleton) kullanmalıyız.
- Yeni boş bir sahne oluşturun ve bir
AudioStreamPlayerekleyip adınıMusicPlayeryapın.
AudioStreamPlayer — MusicPlayer olarak adlandırıldı
- Ses dosyanızı (örneğin
House In a Forest Loop.ogg) Stream alanına sürükleyin ve Autoplay (Otomatik Oynat) ayarını aktif edin.
Stream atandı ve Autoplay açık
- Sahneyi
music_player.tscnolarak kaydedin. - Üst menüden Project > Project Settings > Globals > Autoload sekmesine gidin. Kaydettiğiniz bu sahneyi seçip Add butonuna tıklayın.
music_player.tscn Autoload olarak kaydedildi
Tebrikler! Artık bu node oyun başladığında arka planda global olarak yüklenecek ve sahneler değişse bile müzik asla kesilmeyecek.
AnimationPlayer ile 3D Objeleri Canlandırmak
Karakterimiz hareket ediyor ama sadece kayıyor gibi duruyor. Godot’nun güçlü AnimationPlayer node’unu kullanarak ona süzülme (float) animasyonu ekleyelim.
player.tscnsahnesini açın vePlayernode’una birAnimationPlayerçocuğu ekleyin.
Animation dock: araç çubuğu, track editörü ve zaman çizelgesi
- Ekranın altında açılan Animation panelinden Animation > New diyerek
floatadında bir animasyon oluşturun. - Animasyon süresini
1.2saniye yapın, Autoplay ve Loop (Döngü) butonlarını aktif hale getirin.
Keyframe (Anahtar Kare) ve Easing Eğrileri
Animasyonları hazırlarken Player veya Pivot node’unu değil, doğrudan 3D modelimiz olan Character node’unu hareket ettireceğiz.
- Zaman çizelgesinde 0.3 saniyeye gelip Character’in Position (Konum) özelliğine, 0.1 saniyeye gelip Rotation (Döndürme) özelliğine birer keyframe (anahtar) ekleyin.
- 0.5 saniyeye gelip karakteri Y ekseninde yukarı taşıyın ve biraz öne eğerek (Rotation X: 8) tekrar keyframe alın.
- 1.2 saniyede karakteri tekrar başlangıç noktasına yakın bir yere indirip geriye yatırarak (Rotation X: -9) bitiş keyframe’lerini ekleyin.
💡 İpucu: Animasyonun robotik görünmemesi için eklediğiniz keyframe’leri farenizle seçip Inspector panelindeki Easing eğrisini sağa (ease-in) veya sola (ease-out) kaydırabilirsiniz. Bu sayede hareket başlangıçta hızlı, bitişe doğru yavaşlayarak “doğal bir zıplama/süzülme” hissi verir.
Koda Bağlamak: Hıza Göre Animasyon İvmesi
Karakter yürürken animasyonun hızlanmasını istiyoruz. player.gd dosyanızdaki _physics_process fonksiyonuna şu kodları ekleyebilirsiniz:
1
2
3
4
5
6
7
8
# Karakter hareket ediyorsa animasyonu 4 kat hızlandır
if direction != Vector3.ZERO:
$AnimationPlayer.speed_scale = 4.0
else:
$AnimationPlayer.speed_scale = 1.0
# Zıplarken karakterin öne/arkaya eğilmesi
$Pivot.rotation.x = PI / 6.0 * velocity.y / jump_impulse
Kodun Satır Satır Açıklaması:
if direction != Vector3.ZERO:: Oyuncu herhangi bir tuşa basıp hareket ediyorsa (yön sıfır değilse).$AnimationPlayer.speed_scale = 4.0: Yukarıda yaptığımız süzülme (float) animasyonunu, karakter yürürken daha canlı / koşturuyormuş gibi görünmesi için normalız hızının 4 katına (4.0) çıkarırız.else:: Karakter hareket etmiyorsa (duruyorsa).$AnimationPlayer.speed_scale = 1.0: Animasyon hızını normal (1x) değerine geri alırız ki karakter yerinde sakince soluklansın.$Pivot...: Bu uzun satır son bir profesyonel dokunuştur. Karakterin zıplarken gerçekçi biçimde öne / arkaya eğilmesini sağlar.velocity.y / jump_impulse: Karakter havalandığında hızı çok yüksektir, tepeye ulaştığında sıfırlanır, düşerken eksi olur. Bu değeri zıplama gücüne (20) bölerek -1 ile 1 arasında yumuşak bir oran (+ hızlanış, - düşüş) elde ederiz.PI / 6.0: 30 derecelik bir açıyı temsil eder. (Animasyon çok abartılı yatmasın diye).$Pivot.rotation.x = ...: Bulduğumuz bu oranı, 30 dereceyle çarpıp modelimizin (Pivot) ileri yatma ekseni olan X’e işleriz. Böylece karakter yukarı çıkarken şahlanır (geriye yatar), düşerken ise tam tersi peline doğru süzülerek süper kahraman inişi yapar.
Aynı animasyon yapısını Mob (Düşman) sahnenize de kopyalayabilir ve speed_scale değerini düşmanın rastgele hızına orantılayarak her düşmanın kendi hızına uygun animasyonla hareket etmesini sağlayabilirsiniz.
Konuyla ilgili Youtube videosu aşağıdadır…
Bölüm Özeti
Harika bir ilerleme kaydettiniz! Bu bölümde;
- Katman (Layer) ve Maske (Mask) mantığıyla 3D çarpışma kurallarını yazdınız.
- Vektör matematiğini (Dot Product) kullanarak “üstten basma” mekaniğini kodladınız.
Area3Dkullanarak zıplamaya duyarlı bir “Game Over” hitbox’ı oluşturdunuz.
Serinin Özeti ve Final
Başardınız! 🎉 Sıfırdan başlayarak Godot Engine’in felsefesini, node ve sinyal yapılarını, 2D oyun dinamiklerini ve nihayetinde 3D dünyaya geçişi, fizik kurallarını ve animasyon sistemini öğrendiniz.
Bu süreçte yazdığınız kodlar ve kurduğunuz sahneler, bundan sonra yapacağınız çok daha büyük ve gelişmiş projeler için yıkılmaz bir temel oluşturdu. Godot Engine yolculuğunuzda kendi oyunlarınızı tasarlamaya artık tamamen hazırsınız.
Başka rehberlerde ve yeni oyunlarınızda görüşmek üzere, iyi geliştirmeler!

