Godot Yılan Klonu 3 – Yılan ve alt sahneler

Evet arkadaşlar Godot oyunumuza kaldığımız yerden devam ediyoruz. Artık biraz daha hızlanabiliriz. Aşağıdaki yazıları okumadıysanız, lütfen önce onları okuyunuz. Godot ilişkin temel bilgileri orada bulabilirisiniz.

Godot Yılan Klonu 1 – Dizin Yapısı ve Git Sayfası

Godot Yılan Klonu 2 – Ayarlar ve Temel Sahneler

Ayrıca bu yazım ile yapmış olduğum değişikliklere aşağıdaki respository’den ulaşabilirsiniz:

https://github.com/yazilimperver/BegumSnakeRider

Bu yazımda geliştireceğimiz sahneler şu şekilde:

  • Baş (“Head”) sahnesi: Yılan sahnesi içerisinde, temel hareketleri kontrol eden sahne,
  • Kuyruk (“Tail”) sahnesi: Yılan karakterimizin vücut parçalarını oluşturan sahne,
  • Meyve (“Food”) sahnesi: Oyun içerisinde yılan karakterimizin uzamasına yardım olacak olan sahne,
  • Yılan (“Snake”) sahnesi: Oyun çizim ve mekaniklerinden sorumlu sahne.

Bu sahneleri scene dizini altına (ilk yazıda detayları bulabilirsiniz) ve ilgili betikleri de scripts dizini altına oluşturacağız. Aşağıda bu yazı sonunda dizin yapımızın alacağı şekli görebilirsiniz:

Baş (“Head”) Sahnesi

Hemen baş sahnemize geçelim. Bu sahnemiz basitçe yılanımızın başını temsil edecek ve ayrıca hareket kısımlarını da buradan yöneteceğiz. Benzer şekilde yiyecekleri yeme veya çarpma kontrolleri de bu sahne içerisinde olacak. Sahne aşağıdaki öğeleri içeriyor olacak:

  • Head: Area2D Nesnesi. Bu nesne ile çarpma kontrollerini kolay bir şekilde yapacağız. Bunun içinde sağdaki Node panelini açıp “bodyEntered” sinyalini, baş için oluşturduğumuz script içerisindeki fonksiyona (onHead_body_entered) bağlayacağız.
  • Sprite: Bu nesne ile yılan başımıza bir görünüm kazandıracağız. Şimdilik bu amaçla “assets\images\headItem.png” resmini kullanacağız. Dilerseniz farklı bir imaj ile değiştirebilirsiniz ama boyutunun aynı olmasına şimdilik dikkat edin.
  • CollisionShape2D: Bu da aslında baş nesnemize ilişkin çarpma alanını tanımlamak için kullanacağız. Burada Shape kısmından RectangleShape2D oluşturacağız. Daha sonra bu alanın üzerinde bir kere tıklayıp, dikdörtgenin özelliklerini açalım ve oradan da Extents değerlerini 15 yapalım (bu değer nereden geliyor diye soracak olursanız ki olsanız iyi olur. Bunlar baş için kullanacağımız resmin boyut [30×30] bilgilerinden geliyor). Bunu daha sonra, yanındaki göze tıklayarak gizleyebilirsiniz.
  • Tween: Bu da animasyon için kullanılan bir node. Bunu ölme animasyonu için kullanacağız.

Evet şimdi gelelim, baş node’umuza hayat verecek olan betiği yazmaya. Aşağıda bu betiği bulabilirsiniz.

Buradaki metotlara ilişkin açıklamaları, betik içerisine ekliyorum, anlaşılmayan bir nokta olursa lütfen yorumlar kısmında sorun. Betiğin başında olan signal anahtar kelimesi ile belirtilmiş satırlar, bu sahneden diğer sahnelere sunulan sinyalleri ifade etmektedir (yukarıdaki bodyEntered gibi, QT deki sinyal/slotlar gibi). Bunlar aracılığı ile üst sahneler ile haberleşmeyi/etkileşimi kolay bir şekilde halledebileceğiz. Bu sinyalleri betik içerisinde cağırmak için emit_signal(“sinyalİsmi”) ni kullanıyoruz.

Burada bilmemiz gereken bir diğer konu, genel olarak yılanımız nasıl hareket ettirdiğimize ilişkin mantık:

  • Yılan için harekette kullanmak üzere bir yön değişkenimiz var ki, bu da changeDirection ile belirleniyor. Bu fonksiyon da, kullanıcı üst saheneler tarafından cağrılıyor olacak ve mevcut yılan yönüne göre yılana yön verecek.
  • Daha sonra, bu yöne göre her hareket sayacımız dolduğunda, onMoveTimer_timeout metodumuz aracılığı ile yılanımızın kelleyi şerifesini, kuyruklarımız ile hareket ettireceğiz. Burada yine bu fonksiyon dışarıdan çağrılıyor olacak (dikkatiniz celbetti mi bilemiyorum ama bu tarz fonksiyonların cağrılmasının kontrolünü hep dışarıya verdiğimi fark etmişsinizdir. Bu sayede oyun kontrolleri daha basit ve daha kontrollü olduğuna inanıyorum).
  • Son olarak her bir hareket hesaplandıktan sonra, üst sahneyi headMoved sinyali ve yeni konum ile bilgilendiriyoruz.
  • Baş ki, yukarıda da bahsettiğimiz üzere Area2D nesnesi olarak tanımladık, herhangi bir başka nesnenin üzerine geldiğinde onHead_body_entered çağrılıyor olacak. Burada eğer, üst üste gelinen nesne:
    • Meyve ise, ki bunu atanan “Food” grup ismi üzerinden anlayacağız, foodCollected sinyali yayınlanacak,
    • Engel ise, ki bunu da atana “Obstacle” grup ismi üzerinden anlayacağız ve obstacleHit sinyali yayınlanacak ve çarpma animasyonu başlatılacak.
  • Yılanın başı ve oyunumuzun temel koşum mantığını görmüş olduk. Şimdi diğer sahnelere bir göz atacağız ama önceesinde bu sahnemizi yılan sahnemize ekleyelim:
    • Önce yılan sahnemizi açalım,
    • Yılan kök düğümüne gidelim ve sağ tıklayarak, çıkan menüden “Instance Child Scene”‘ı seçelim,
    • Çıkan pencereden de yeni oluşturduğumuz baş sahnesine ekliyoruz.

Kuyruk (“Tail”) Sahnesi

Şimdi kuyruk sahnemize geçelim. Bu sahnemiz basitçe yılanımızın kuyruğundaki elemanları temsil edecek ve baş sahnesine çok benzer bir yapıda:

  • Tail: Static2DBody Nesnesi. Bu nesne ile kuyruğa fiziksel bir kabiliyet kazandırmış olduk,
  • Sprite: Bu nesne ile yılan gövdemize de bir görünüm kazandıracağız. Şimdilik bu amaçla “assets\images\blueItem.png” resmini kullanacağız,
  • CollisionShape2D: Bu da kuyruk nesnemize ilişkin çarpma alanını tanımlamak için kullanacağız ve baş ile aynı şekilde oluşturacağız. Bunu da daha sonra, yanındaki göze tıklayarak gizleyebilirsiniz,
  • Tween: Bu da animasyon için kullanılan bir node. Bunu ölme animasyonu için kullanacağız.

Kuyruk sahnemize ilişkin betiğimiz de aşağıdaki gibi:

Çok daha basit bir betik. Farklı olarak destroy_self fonskiyonunu görüyorsunuz ki, bu da sahne ile işimiz bitince yapmamız gereken bir iş. Bu sahnemizi direk yılan sahnemize, sahne ağacı üzerinden eklemeyeceğiz. Sizce nasıl kullanacağız? Doğru tahmin ettiniz, yılan sahnesi içerisinde yılanımızın meyve yediğini anladığımız anda betik içerisinde oluşturacağız.

Meyve (“Food”) Sahnesi

Şimdi bir de meyve sahnemizi oluşturalım. Bu sahne de kuyruğa benziyor ve herhangi bir betik içermiyor.

  • Food: Static2DBody Nesnesi. Bu nesne ile meyvelere fiziksel bir kabiliyet kazandırmış olduk.
  • Sprite: Bu nesne ile meyve nesnelerimize bir görünüm kazandıracağız. Şimdilik bu amaçla “assets\images\fruitItem.png” resmini kullanacağız.
  • CollisionShape2D: Bu da meyve nesnemize ilişkin çarpma alanını tanımlamak için kullanacağız ve baş ile aynı şekilde oluşturacağız. Bunu da daha sonra, yanındaki göze tıklayarak gizleyebilirsiniz.

Son olarak, engelden farklı olarak çarpma sırasında bunun meyve olduğunu anlamak için gruplama özelliğini kullanacağız. Bu amaçla, yine “node panel”‘ini açıyoruz ve “Manage Group”s altına “Food” yazıp Add’e tıklıyoruz. Bu sahneye ilişkin işimiz de bu kadar.

Yılan (“Snake”) Sahnesi

Şimdi gelelim yılan sahnemize. Daha önceki yazılarımda da bahsettiğim gibi, Godot içerisinde oyun bileşenlerinizi iç içe geçmiş sahnelerden oluşturuyorsunuz. Yılan sahnemiz de aslında bizim oyun sahnemizin bir parçası olacak ve o da kendi içerisinde bir takım sahneler içeriyor olacak. Hemen bir bakalım:

  • TailContainer: Yılanımız büyüdükçe, kuyruk parçalarını bunun içerisine koyacağız,
  • SnakeHead: Yılan başını ifade eden gömülü sahnemiz. Bunun detayları aşağıda anlatacağım,
  • MoveTimer: Yılanın hareketi için kullanacağız,
  • [Eat|Hit]Sound: Meyve yeme ve duvar/engellere çarpma seslerimiz,
  • InitialPosition: Yılanımızın harekete başlayacağı ilk konum.

Şimdi artık yılan sahne betiğine bir göz atmanın zamanı geldi.
Öncelikli olarak oluşturduğumuz MoveTimer sayacının “timeout” sinyalini baş sahnesindeki onMoveTimer_timeout fonksiyonu ile bağlıyoruz. Bu sayede, yılan başı sayaç ile tetiklenerek, hareket mekaniğini çalıştıracak.

Daha sonra yapacağımız şey, klavye aracılığı ile girdileri almak olacak (ileride belki farklı girdileri de kullanırız 😉 ). Bunun için öncelikle “Project->Project Settings” altındaki “Input Map” sekmesine gidiyoruz. Burada bir kısım girdi eşleştirmeleri yapacağız. Bu ayarlar ile uygulama içerisinde, “ui_xxx” ile başlayan olaylara, çeşitli klavye/fare/dokunmatik girdileri atayabiliyoruz. Oyunumuz için şimdilik aşağıdaki eşlemeleri yapmamız yeterli:

  • ui_up: Up (keyboard)
  • ui_down: Down (keyboard)
  • ui_left: Left (keyboard)
  • ui_right: Right (keyboard)

Bu ayarlamaları yaptıktan sonra, uygulama içerisinden bu tuşlara basılma bilgilerini alabileceğiz. Bunun için de _input fonksiyonu kullanılmakta. Bu fonksiyon ile baş sahnesi, girdilerden haberdar edilecek.

Şimdi sırayla önemli bir kaç fonksiyonlarda neler yaptığımıza bakalım. Diğer fonksiyonlara ilişkin açıklamalara betik içerisinden ulaşabilirsiniz.

  • _ready fonksiyonu: Öncelikle sinyallerin birbirleri ile ilişkilendirilmesi, başın ilk pozisyona alınması, gövde bileşenlerinin oluşturulması ve nihai olarak sayacın başlatılmasını gerçekleştirir.
  • setupSignals fonksiyonu: Tanımlamış olduğumuz sinyalleri ilgili fonksiyonlar ile bağlandığı fonksiyon burası. Bunlar sırayla yılan ile baş (inputReceived) ve baş ile yılan sahnelerindeki fonksiyonlar (obstacleHit, headMoved, foodCollected) ile bağlıyoruz.
  • moveTail fonksiyonu: Baş pozisyonu değiştiğinde, en arkadaki gövde parçasını çıkarıp, baş konumuna yeni bir gövde parçası ekliyoruz. Eğer meyve yenilmiş ise, gövdeyi bir birim uzatıyoruz.

Evet arkadaşlar bu adımlar ile birlikte artık yılan oyunumuzu ete kemiğe büründürmüş olduk. Yapacağımız son şey, engelleri tanımlamak olacak. Meyve sahnesinde olduğu gibi, background sahnemizi açıyoruz. Daha sonra, bütün Wall çocuk düğümleri için “node panel”‘ini açıyoruz ve “Manage Group”s altına “Obstacle” yazıp Add’e tıklıyoruz.

Artık F5 e basarak oyunumuzu başlatabiliriz. Aşağıdaki gibi oyun ekranımızı görmenizi bekliyorum. Göremezseniz, yorumlar kısmında sizleri bekliyor olacağım 🙂

Uygulamayı daha iyi tanıyabilmek için, muhakkak yukarıdaki adımların üzerine eklemeler yaparak, uyarlamalar yapın. Bir sonraki yazıda, meyvelere can vereceğiz, oyun alanı ile ilgili sıkıntıyı gidereceğiz (acaba ne???), oyunumuzu android’te çalışabilecek hale getireceğiz. O zamana kadar kendinize iyi bakın. İyi eğlenceler.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

This site uses Akismet to reduce spam. Learn how your comment data is processed.