Godot Engine Eğitim Serisi - Bölüm 9: 3D Dünyaya Geçiş ve Oyuncu Kontrolü
Godot ile 3D oyun geliştirme: CharacterBody3D, kamera, yerçekimi ve 3D hareket kodu. Squash the Creeps serisi Türkçe eğitim.
2D oyun projemizi başarıyla tamamladıktan sonra artık bir adım ileriye geçme ve ilk 3D oyunumuzu (“Squash the Creeps!”) geliştirme zamanı!
Serinin sonunda bu oyunu yapmış olacaksın — zıplayarak düşmanların üstüne bas!
3D oyun geliştirmek, 2D’ye kıyasla bazı yeni zorlukları beraberinde getirir: Artık derinliği ifade eden bir Z ekseni vardır, 2D’de olduğu gibi ekranın tamamı oyun sahneniz değildir (kamerayı özel olarak yönetmeniz gerekir) ve fizik motoru biraz daha farklı çalışır. Ancak endişelenmeyin, hepsini adım adım çözeceğiz!
Bu projede ihtiyacınız olacak bazı görsel ve animasyon içeriklerini buradan indirebilirsiniz.
3D Oyun Alanını Hazırlama
Oyun mantığını barındıracak ana sahneyi oluşturarak başlayalım. Yeni bir sahne oluşturun ve kök node olarak sıradan bir Node (isim: Main) ekleyin.
Karakterlerin boşluğa düşmemesi için 3D uzayda fiziksel bir zemin inşa etmeliyiz. 3D’de zemin veya duvar gibi hareketsiz çarpışma objeleri için StaticBody3D kullanılır.
Mainnode’una birStaticBody3Dçocuğu ekleyin ve adınıGroundyapın.- Fiziksel sınırları belirlemek için
Groundnode’una birCollisionShape3Dekleyin ve Inspector’dan şeklini (Shape)BoxShape3Dolarak seçin. Bu kutunun boyutlarını (Size) X: 60, Y: 2, Z: 60 olarak ayarlayın.
Zemin için en uygun şekil BoxShape3D — düz ve güvenilir
BoxShape3D boyutu 60×2×60 olarak ayarlandı
- Çarpışma kutuları oyun içinde görünmez. Zemini gözle görebilmek için
Groundnode’una birMeshInstance3Dekleyin, Mesh özelliğiniBoxMeshyapın ve onun da boyutlarını 60, 2, 60 olarak belirleyin.
Görsel zemin için BoxMesh kaynağı oluşturuyoruz
Görsel zemin tam ekranı kaplar hâlde
Sahneyi biraz aydınlatmak için Main node’una bir DirectionalLight3D ekleyin. Gerçekçi bir görünüm için Inspector’dan Shadow (Gölge) özelliğini aktif hale getirmeyi unutmayın.
Shadow açıldığında sahne çok daha gerçekçi görünür
Oyuncu (Player) Sahnesini Kurmak
Şimdi oyuncu karakterini ayrı bir sahne olarak oluşturmalıyız.
- Scene > New Scene ile yeni bir sahne oluşturun ve kök node olarak
CharacterBody3Dekleyip adınıPlayeryapın.
💡 Bilgilendirme:
CharacterBody3D, fizik motoru tarafından değil, tamamen sizin kodlarınızla hareket ettirilen ama çevreyle fiziksel çarpışmalara girebilen bir yapıdır.
- Oyuncu modelini kodla kolayca kendi etrafında döndürebilmek için bir
Node3Dçocuğu ekleyin ve adınıPivotyapın. - 3D model dosyanızı (
player.glb) sürükleyerek buPivotnode’unun çocuğu yapın.
Player > Pivot > Character (player.glb instance’ı)
- Karakterin dünya ile çarpışabilmesi için
Playernode’una birCollisionShape3Dekleyin, şekliniSphereShape3D(Küre) yapın ve modeli saracak şekilde (yaklaşık 0.8 metre yarıçap) boyutlandırıp zemine hizalayın.
Karakterin altında bir küre tel kafes görünür
Çarpışma şeklini zemin düzlemiyle hizalayacak şekilde yukarı taşıyoruz
Girdi (Input) Eylemlerini Tanımlamak
Karakteri hareket ettirmek için 3D eksenlere karşılık gelen tuş atamalarını yapmalıyız. Project > Project Settings > Input Map yolunu izleyerek şu eylemleri ekleyin ve ok tuşlarını atayın:
Input Map — üstten eylem ekleyip alttan tuş atayabilirsin
move_left(Sol Ok)move_right(Sağ Ok)move_forward(Yukarı Ok / Z ekseninde ileri)move_back(Aşağı Ok / Z ekseninde geri)
Dört yön eylemi klavye ve joystick ile eşleştirildi
3D Hareket Kodunu Yazmak
Player node’una bir script ekleyin. 3D fizikle ilgili işlemler için Godot’nun sabit zaman aralıklarıyla çalışan _physics_process() fonksiyonunu kullanacağız.
Aşağıdaki GDScript kodunu dosyanıza yapıştırın:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
extends CharacterBody3D
@export var speed = 14
@export var fall_acceleration = 75
var target_velocity = Vector3.ZERO
func _physics_process(delta):
var direction = Vector3.ZERO
# Girdileri 3D eksenlere göre dinliyoruz (X yatay, Z derinlik)
if Input.is_action_pressed("move_right"):
direction.x += 1
if Input.is_action_pressed("move_left"):
direction.x -= 1
if Input.is_action_pressed("move_back"):
direction.z += 1
if Input.is_action_pressed("move_forward"):
direction.z -= 1
# Çapraz harekette hızı normalleştirmek için
if direction != Vector3.ZERO:
direction = direction.normalized()
$Pivot.basis = Basis.looking_at(direction)
# Yerden Yüksekteyse Yerçekimi Uygula
if not is_on_floor():
target_velocity.y = target_velocity.y - (fall_acceleration * delta)
# X ve Z eksenlerinde yatay hız hesaplaması
target_velocity.x = direction.x * speed
target_velocity.z = direction.z * speed
# Hızı karaktere aktar ve hareket ettir
velocity = target_velocity
move_and_slide()
Kodun Satır Satır Açıklaması:
extends CharacterBody3D: 3D dünyada fiziksel etkileşimlere girebilen (duvarlara çarpan) bir karakter gövdesi düğümü kullandığımızı belirtir.@export var speed = 14: Editörden (Inspector’dan) değiştirilebilir, hareket hızımızı 14 olarak ayarlayan değişken.@export var fall_acceleration = 75: Yine editörden değiştirilebilen, yerçekiminin (aşağı düşüşün) ivme hızını belirleyen değişken.var target_velocity = Vector3.ZERO: Hedef hızımızı tutan değişken. X (sağ/sol), Y (yukarı/aşağı) ve Z (ileri/geri) olmak üzere üç değeri de 0 olarak başlatıyoruz.func _physics_process(delta):: 3D fizikle ilgili her türlü hareket ve çarpışma kontrolünü, oyunun o anki kare hızından (delta) bağımsız ve sabit adımlarla yapmamızı sağlayan ana motor fonksiyonumuzdur.var direction = Vector3.ZERO: Her yeni karede (çalışmada) oyuncunun gitmek istediği yönü geçici olarak sıfırlar.if Input.is_action_pressed("move_right"):vb.: Oyuncunun klavyesini dinliyoruz. 2D bölümünden farklı olarak burada yukarı/aşağı gitmek Y değil, kameradan uzaklaşıp yakınlaşmak, yani Z eksenidir. Z ekseni derine doğru gittiği için,move_forward(ileri git) dendiğinde yönün Z eksenini küçültürüz (-1),move_backile Z eksenini büyütürüz (+1). Sağa sola gitmek ise yine eskisi gibi X eksenidir.if direction != Vector3.ZERO:: Eğer oyuncu bir tuşa basıp yön değiştirdiyse…direction = direction.normalized(): Çapraz giderken çok hızlı gitmesini kes, hızı 1 birime sabitle.$Pivot.basis = Basis.looking_at(direction): Bu satır, karakterin modelini döndürmek içindir. Node3D altındaki “Pivot” objemizi buluruz.Basisyapısı 3D dünyadaki çevirmeleri yönetir..looking_at(direction)diyerek, o an yürünen yöne doğru bu objenin yüzünü döndürürüz. (Artık oyuncu sağa giderken modeli de sağa dönmüş olur).if not is_on_floor():: Godot’nun müthiş kolaylıklarından biri. “Eğer karakter zeminde (floor)değilse” (yani havadaysa/düşüyorsa) demek.target_velocity.y = target_velocity.y - (fall_acceleration * delta): Hedef hızımızın Y (yukarı/aşağı) değerine, belirlediğimiz düşüş ivmesini (75) zamanla (delta) çarparak çıkart (-). Yani karakteri sürekli yere doğru çek.target_velocity.x = direction.x * speed: Gitmek istediğimiz (basılan) X yönünü, son süratimizle (14) çarparak asıl yatay hedef hızımıza (x) yaz.target_velocity.z = direction.z * speed: Gitmek istediğimiz derinlik (Z) yönünü hızımızla çarpıp hedef derinlik hızına (z) yaz.velocity = target_velocity: Matematiksel tüm hesaplamalar (yerçekimi + sağ/sol + ileri/geri yönler) bitti. Kendi hesapladığımız bu hedef hızı, CharacterBody3D’nin asıl motoruna (velocity) teslim et.move_and_slide(): Nihayet tüm bu hız bilgilerini alarak, 3D dünyadaki duvarları ve engelleri hesaba katarak karakteri pürüzsüzce kaydırarak hareket ettir (duvara takılmadan yanından kayıp gitmesini sağlar).
Bu kodda neler yaptık?
- 3D ortamda yer düzlemi X ve Z eksenlerinden oluşur (Y ekseni yukarı/aşağıdır). Hareketleri bu eksenlerde hesapladık.
$Pivot.basis = Basis.looking_at(direction)ile 3D modelimizin (Pivot üzerinden) her zaman gittiği yöne doğru bakmasını sağladık.is_on_floor()metoduyla karakterin havada olup olmadığını algılayıp, havadaysafall_accelerationdeğerimizle onu aşağı (Y ekseninde eksiye) çektik.- En sonunda
move_and_slide()ile 3D hareketi güvenli ve pürüzsüz bir şekilde gerçekleştirdik.
Kamerayı Yerleştirmek (Ortografik)
3D dünyada bir kameranız yoksa siyah bir ekrandan başka bir şey göremezsiniz.
Mainsahnesine geri dönün vePlayersahnenizi bir “Instance” (Örnek) olarak oyun alanına ekleyin.- Sahneye bir
Camera3Dnode’u ekleyip yukarıdan oyuncuya bakacak şekilde konumlandırın. - Bu tür oyunlar için “Perspektif” yerine Ortografik (Orthogonal) kamera kullanmak mesafeleri okumayı kolaylaştırır. Kamerayı seçip Inspector’dan Projection ayarını
Orthogonalyapın ve Size değerini19olarak ayarlayın.
Konuyla ilgili Youtube videosu aşağıdadır…
Bölüm Özeti
Tebrikler, artık 3D dünyada hareket eden ve nesnelere çarpan bir karakteriniz var! Bir sonraki bölümde, oyun alanına düşmanları spawn etmeyi (oluşturmayı) öğreneceğiz.