Unity’de Sonsuz Yol Yapımı (İnfinite Road)

Unity’de Sonsuz Yol Yapımı (İnfinite Road)

18 Şubat 2020 0 Yazar: Ahmet Güler

Merhaba, bir önceki yazımızda Unity‘de Bayrak yapmıştık.Bu şekilde bez, kumaş gibi nesneleri Cloth sistemi ile yapabiliyorduk.Bugünkü dersimizde ise, Unity ile endless runner yani sonsuz bir yol yapacağız.Bu şekilde sonsuza giden bir yol yapmanın birçok yolu olmakla birlikte, bende kendime göre bir yolunu göstereceğim.Lafı uzatmadan yeni bir proje oluşturalım ve dersimize başlayalım.

Sahnemizi oluşturmaya başlayalım.

Bu dersimizin senaryosunu söylememe gerek yok diye düşünüyorum.Herhangi bir konsepte yolumuzu oluşturabiliriz.Ben yolu tren rayı şeklinde tasarlayacağım.Böylece sonsuz bir tren yolumuz oluşacaktır.Şimdi ilk olarak, sahnemize bir Cube nesnesi ekleyelim.Bu nesne bizim sonsuz yolumuzu oluşturacak parça olacak.Daha sonra bu nesnemiz için yeni bir etiket oluşturalım.Şimdi Cube nesnemizin Inspector penceresinde bulunan, Box Collider bileşenimizin boyutlarını değiştireceğiz.

Bunun için, “Edit Collider” butonuna basıyoruz.Daha sonra, Scene penceresinden collider boyutunu y ekseninde büyütüyoruz.Bunu yapmamızın neden, parçamızın yeni pozisyonunu tetikleyici ile değiştirebilmektir.Tabi tetikleyicimizi kullamak içinde, Box Collider bileşeninde bulunan “isTrigger” özelliğini aktif etmemiz gerekiyor.Şu anda sahnemiz bu şekilde görünüyor.

Unity-Sonsuz-Yol-Yapımı-how-to-İnfinite-tutorial-Road-endless-runner

Oluşturduğumuz bu Cube nesnesi projemiz için yeterli olacaktır.Başta dediğim gibi, bir tren yolu yapmak istediğim için, bu Cube nesnesinden bir ray parçası yapacağım.Bunu Unity‘de bulunan hazır nesnelerden yararlanarak oluşturuyoruz.Tren raylarının metalini ve tahtalarını, sahnemize yeni Cube nesneleri ekleyerek yapıyoruz.Daha sonra tren raylarının kenarlarına ağaçlar oluşturuyoruz.

Bunları oluşturmak için, Cylinder ve Sphere nesnelerinden yararlanıyoruz.Silindir nesnelerimizi, ağaçların gövdelerini oluşturmak için kullanıyoruz.Yaprakları içinde küre nesnelerimizden yararlanıyoruz.İstediğimiz kaplamaları nesnelerimize ekledikten sonra sonsuz yolumuzu oluşturacak ray parçamız hazır oluyor.Şimdi üzerinde gitmesi için bir tren modeli ekliyoruz.

Bu modelleri internetten bulabilirsiniz.Projemizde dışarıdan bir model kullandığımız için bu modele ekstra olarak, bir Box Collider ve Rigidbody bileşenleri ekliyoruz.Collider, tren modelimizin raylar üzerinde kalması için önem teşkil ediyor.Tetikleyici için fizik gerektiği içinde Rigidbody bileşeni önemli oluyor.Şimdi bu ray nesnemizi Prefab olarak kullanmak için, Project penceresine sürükleyerek bırakıyoruz.Bunları yaptıktan sonra sahnemiz hazır duruma geliyor.

Unity-Sonsuz-Yol-Yapımı-how-to-İnfinite-tutorial-Road-endless-runner

Sonsuz yolumuz için kodlarımızı yazmaya başlayalım.

Bu projede iki adet C# Script dosyası kullanacağız.Bunlardan birini, projemiz başladığı anda belirli sayıda rayı sahnemizde oluşturmak için kullanacağız.Diğerini ise, hem trenimizi hareket ettirmek için hemde rayların pozisyonlarını değiştirmek için kullanacağız.Şimdi ilk script dosyamızı editör ile açalım ve kod yazmaya başlayalım.

public GameObject Ray;
public List<Transform> ParcaListesi = new List<Transform>();
public Transform SonuncuParca;
public int ParcaSayisi;
public float zEkseni;

İlk olarak, değişkenlerimizi oluşturmakla başlıyoruz.İlk satırda, raylarımız için oluşturduğumuz Prefab nesnesini kullanmak için bir GameObject değişkeni oluşturuyoruz.İkinci satırda yeni bir Transform listesi oluşturuyoruz.Bu listede, sahnemizde olan tüm ray parçalarının Transform değerlerini tutacağız.Üçüncü satırda, yeni bir Transform değişkeni daha oluşturuyoruz.Bu değişkende ise, listemizde bulunan son ray parçasının Transform değerlerini tutacağız.

Böylece bir sonraki rayımızı konumlandıracağımız değerleri bileceğiz.Dördüncü satırda int (integer) türünde bir değişken oluşturuyoruz.Bu değişkende ise, projemizi başlattığımız zaman sahnemizde kaç tane ray yolu olacağını belirleyeceğiz.Son satırda, float türünde bir değişken oluşturuyoruz.Bu değişkende ise, ray parçalarımızın z eksenindeki boyutunu tutacağız.Böylece sondaki rayı en öne eklerken, bu değişkendeki değeri artı olarak sayacağız.

zEkseni = 0;
for (int i = 0; i < ParcaSayisi; i++) { }

Şimdi start() fonksiyonumuzun içerisine bu kodları yazıyoruz.İlk satırda, değişkenimizin değerini sıfırlıyoruz.İkinci satırda ise, yeni bir for döngüsü oluşturuyoruz.Bu döngü içerisinde ray parçalarımızı oluşturacağız.Az önce değindiğim gibi, “ParcaSayisi” değişkeninde yer alan değer kadar döngümüz devam edecek.Bu şekilde dinamik olarak ray sayısını azaltabilir yada çoğaltabilirsiniz.

GameObject YeniRay = Instantiate(Ray, new Vector3(0, 0, Ray.transform.localScale.z * i), Ray.transform.rotation) as GameObject;
YeniRay.name = "Ray" + i;
ParcaListesi.Add(YeniRay.transform);

Şimdi döngümüzün içerisinde oluşacak olayları belirlemek için bu kodları yazıyoruz.İlk satırda, yeni bir GameObject değişkeni oluşturuyoruz.Yanlız bu değişken local yani yerel olarak erişilebilir olacak.Daha sonra Instantiate fonksiyonundan yararlanarak, Prefab olarak bekleyen ray parçalarımızı sahnemize ekliyoruz.Bu fonksiyonun parametrelerine bakacak olursak, ilk olarak Prefab nesnemizin eklendiği değişkenimizi çekiyoruz.Daha sonra, yeni pozisyonunu veriyoruz.

Burada dikkat etmeniz gereken z eksenidir.Her döngüde ray parçamızın tam yerine oturması için, Prefab nesnemizin z eksenindeki boyutu ile for döngümüzde ki “i” değişkeninin değerini çarpıyoruz.Örnek olarak, sahneme dört tane ray parçası eklemek istiyorum diyelim.İlk parçanın z eksenindeki konumu, sıfır olacaktır.Çünkü “10 * i = 0” burada i değişkeninin değeri ilk başta sıfırdır.Bu arada, on “10” değeri nereden geldi diyecekseniz, benim oluşturduğum ray parçasının z eksenindeki boyutudur.

Daha sonrakiler, “10 * 1 = 10, 10 * 2 = 20, 10 * 3 = 30, 10 * 4 = 40” şeklinde devam edecektir.İkinci satıra bakacak olursak, sahnemizde ki klon nesnelerine yeni isimler veriyoruz.İsimlerin benzersiz ve sıralı olması açısından yanlarına i değişkeninin değerini ekliyoruz.Yani, “Ray1, Ray2, Ray3” şeklinde nesnelerimizin yeni isimleri olmuş oluyor.Son satırda ise, oluşturduğumuz bu klon nesnelerinin transform özelliklerini listemize ekliyoruz.Bu script dosyamız hazır duruma geldi.

Sahnemizde ki ray parçalarına yeni pozisyonlarını vermek.

Evet bu aşamaya kadar sahnemizde istediğimiz uzunlukta bir tren yolu oluşturduk.Şimdi bu tren yolunda kullandığımız ray parçalarına yeni pozisyonlarını vermemiz gerekiyor.Böylece sonsuz bir yol oluşturabileceğiz.Yazımın başında da dediğim gibi, bu yolu oluşturmanın birden çok yolu var.Ben burada, sahnemde bulunan parçaların yerlerini kaydırarak kullanacağım.

Mesela bu işlemi arkada kalan parçayı yok edip, en öne yeni bir parça klonlayarak da yapabilirsiniz.Ancak bu işlemin performans tarafında ne derecede etkisi olur orası size kalmış.Dediğim gibi, ben ilk başta parçalarımı klonlayıp daha sonra bu parçaların yerlerini değiştirmeyi daha uygun gördüm.Şimdi ikinci scriptimiz için kodları yazmaya başlayalım.

public Camera Kamera;
public float TrenHizi; 
public int ParcaNo;
public yol YolScripti;

Yine ilk olarak bize lazım olacak değişkenleri oluşturmakla başlıyoruz.İlk satırda Camera değişkenimizi oluşturuyoruz.Bu değişken ile ana kameramızı kontrol edeceğiz.İkinci satırda, float türünde bir değişken oluşturuyoruz.Bu değişkende, tren nesnemizin hızını kontrol edeceğiz.Üçüncü satırda int (integer) türünde bir değişken oluşturuyoruz.Bu değişkende ise, Transform listemizde bulunan elemanların sıra numarasını tutacağız.Son satırda ise, ilk scriptimize erişmek ve oradaki verileri değiştirmek için bir değişken oluşturuyoruz.

Kamera = Camera.main;
YolScripti = GameObject.FindWithTag ("YolKontrolcusu").GetComponent<yol> ();
TrenHizi = 5f;

Şimdi start() fonksiyonumuzun içerisine bu kodları yazıyoruz.İlk satırda, değişkenimize ana kameramızı (camera.main) tanımlıyoruz.İkinci satırda değişkenimize, etiketi “YolKontrolcusu” olan nesnemizin üzerindeki script bileşenini tanımlıyoruz.Böylece diğer script dosyamızda bulunan değişkenlere erişebileceğiz.Son satırda ise, değişkenimize bir değer atıyoruz.Böylece tren hızımızı belirleyebileceğiz.

Kamera.transform.position = new Vector3(Kamera.transform.position.x, Kamera.transform.position.y, transform.position.z);
transform.Translate (Vector3.forward*TrenHizi*Time.deltaTime);

Bu kodları update() fonksiyonumuzun içerisine yazıyoruz.Burada trenimizi ve kameramızı kontrol ediyoruz.İlk satıra bakacak olursak, kameramızı için yeni bir pozisyon oluşturuyoruz.X ve y eksenlerinde ki pozisyonları sabit kalırken, z ekseni için tren nesnemizin z eksenindeki pozisyonu alıyoruz.İkinci satırda ise, tren nesnemizi hareket ettiriyoruz.Bunu Translate fonksiyonu ile yapıyoruz.Bu hızı Time.deltaTime fonksiyonu ile çarparak her karede aynı olacak bir hız elde ediyoruz.

void OnTriggerExit(Collider Kontrol) { }

Şimdi ray parçalarımızın pozisyonlarını değiştirmeye gelelim.Bunun için hatırlarsanız, sahnemizi oluştururken collider boyutu ile oynamıştık ve “isTrigger” özelliğini aktif etmiştik.İşte şimdi yeni bir fonksiyon oluşturuyoruz.Bu yani OnTriggerExit fonksiyonu ile çarpışmayı kontrol edeceğiz.Trenimiz üzerinde ray parçası ile teması kestiği  anda “Exit” kodlarımız tetiklenecek ve üzerinde bulunduğu ray parçası yeni pozisyonuna gidecek.

if (Kontrol.gameObject.tag == "yol") {
   ParcaNo = YolScripti.ParcaListesi.IndexOf(Kontrol.gameObject.transform);
   YolScripti.zEkseni += YolScripti.ParcaListesi[ParcaNo].localScale.z;
   YolScripti.SonuncuParca = YolScripti.ParcaListesi[YolScripti.ParcaListesi.Count - 1].transform;
   YolScripti.ParcaListesi[ParcaNo].position = new Vector3 (0,0,(YolScripti.SonuncuParca.position.z - YolScripti.ParcaListesi[ParcaNo].position.z) + YolScripti.zEkseni);
}

Şimdi tetikleyici fonksiyonumuzun içerisine bu kodları yazıyoruz.İlk satırda yeni bir koşul oluşturuyoruz.Çarpışma gerçekleşen nesnenin etiketi “yol” ise koşulumuz doğru oluyor.İkinci satırda, temas gerçekleşen ray parçamızın index yani sıra numarasını çekiyoruz.Bunu IndexOf fonksiyonu ile yapıyoruz.Üçüncü satırda, diğer script dosyamızda bulunan “zEkseni” değişkeninin değerini arttırıyoruz.Bunu yaparken ray parçamızın z ekseninde ki boyutunu referans alıyoruz.

Dördüncü satırda, yine diğer script dosyasında bulunan “SonuncuParca” değişkenine erişiyoruz.Bu değişkenin değerini, listemizde yer alan sonuncu elemanın Transform özelliklerine eşitliyoruz.Son satırda ise, yine diğer script dosyasından çektiğimiz liste değişkenimizin o anki elemanının pozisyon değerlerini değiştiriyoruz.Yeni pozisyon değerleri için x ve y eksenleri sıfır “0” olarak belirlenirken z ekseni için küçük bir hesap yapıyoruz.Burada listemizde bulunan son elemanın z eksenindeki değerinden, trenimizin üzerinde bulunduğu parçanın z eksenindeki değerini çıkartıyoruz.

Daha sonra bu sonuca yine diğer script dosyamızda ki, “zEkseni” değişkeninin değerini ekliyoruz.Buradaki işlemi biraz açalım.Örnek olarak 4 tane ray parçamız var.İlk baştaki rayı parçasını son parça haline getirmek için, “(40 – 0) + 10 = 50” gibi bir işlem yapıyoruz.Kırk “40” değeri son parçamızın z eksenindeki pozisyonu olurken, sıfır “0” değeri ise ilk parçamızın z eksenindeki pozisyonu oluyor.Artı on “10” ise, bu parçalarımızın z eksenindeki boyutunu temsil ediyor.

YolScripti.ParcaListesi.Add(YolScripti.ParcaListesi[ParcaNo]);
YolScripti.ParcaListesi.Remove(YolScripti.ParcaListesi[ParcaNo]);

Sonsuz yolumuzu oluştururken, her zaman listemizde bulunan son elemanın pozisyon değerlerini baz aldık.Ancak listemizdeki son eleman sabit bir şekilde durursa, yolumuz bir süre sonra bozulmaya başlayacaktır.Bunun önüne geçmek için, trenimizin üzerinden geçtiği ray parçasını listeden silip yeniden eklememiz gerekiyor.Böylece son eklenen parça olduğu için, Transform listemizde de, son sırada yer alacaktır.

Bu şekilde liste elemanları içerisinde de bir döngü oluşturmuş olacağız ve yaptığımız pozisyon hesaplamaları her zaman doğru olacaktır.Tüm bu işlemler için, Add ve Remove fonksiyonlarından yararlanıyoruz.Evet bu şekilde ikinci script dosyamızı da tamamlamış oluyoruz.

Bu projemizin de sonuna geldik.Yapmamız gereken tek bir şey kaldı.O da, script dosyalarımızı nesnelerimize eklemek.İlk script dosyamız için boş bir nesne oluşturuyoruz ve bu nesneye sürükleyerek bırakıyoruz.Daha sonra, Prefab nesnemiz için oluşturduğumuz bölüme Project penceresinde bulunan nesnemizi ekliyoruz.İkinci script dosyamızı ise, tren nesnemizin üzerine sürükleyip bırakıyoruz.İşte bu kadar.Bir sonraki yazıda görüşmek üzere…

Unity-Sonsuz-Yol-Yapımı-how-to-İnfinite-tutorial-Road-endless-runner