Unity’de Havalı Süspansiyon Yapımı (Air Suspension)

Unity’de Havalı Süspansiyon Yapımı (Air Suspension)

9 Ağustos 2020 0 Yazar: Ahmet Güler

Merhaba, bir önceki dersimizde Unity ile maskeleme yapmayı öğrenmiştik.Bu dersimizde ise, Unity‘de projelerimizde kullanacağımız araç modellerine, havalı süspansiyon eklemeyi öğreneceğiz.Bunu yapmak için birden fazla yolumuz bulunuyor.Ancak ben daha iyi anlaşılması için size en basit yöntemi göstereceğim.Şimdi lafı uzatmadan Unity‘de yeni bir proje oluşturalım ve dersimize başlayalım.

Sahnemizi hazırlamaya başlayalım.

Öncelikle bu projede belirlediğimiz tuşlara basarak sahnemizde yer alan araç modelinin süspansiyonlarını, havalı süspansiyon gibi simüle etmeyi deneyeceğiz.Tabi ne kadar fazla detayı göz önüne alırsak, doğru orantılı olarak yapmış olduğumuz havalı süspansiyon sistemi de, o kadar başarılı olur.Ancak bu yazının amacı, diğer yazılarımda da olduğu gibi nasıl yapıldığını ve işin mantığını göstermek olduğu için, ben fazla detaya inmeyeceğim.

Şimdi sahnemize yeni bir Plane nesnesi ekliyoruz.Bu nesne bizim zeminimizi oluşturacaktır.Daha sonra internetten kolaylıkla bulabileceğimiz, 3D bir araç modelini seçiyoruz ve projemize ekliyoruz.Seçtiğimiz modeli sahnemize ekledikten sonra, öncelikle 3d araç modelimizin parçalarını Hierarchy penceresinde düzenlememiz gerekiyor.Bunu yapmamızın nedeni, projemizde daha düzenli çalışmak ve aradığımız şeyi kolaylıkla bulabilmek içindir.

Unity-Havalı-Süspansiyon-Yapımı-How-Does-Air-Suspension-Work

Evet araç modelimizin parçalarını hiyerarşik olarak düzenledikten sonra, modelimizin gövde kısımını seçiyoruz.Daha sonra Inspector penceresine gelerek, bu nesne için yeni bir etiket oluşturuyoruz.Bunu yapmamızın nedeni birazdan yazacağımız kod bölümünde, araç gövdesine kolaylıkla ulaşabilmek içindir.Bu arada Hierarchy penceresine dikkat ettiyseniz, kullandığım araç modelinde tekerler ve gövde ayrı olarak modellenmiş.

Bu yüzden aracı kolaylıkla alçaltıp/yükseltebileceğim.Eğer sizin kullandığınız model, bu şekilde kısımlara ayrılarak modellenmediyse birazdan yapacağımız işlemler sizin için sıkıntı yaratacaktır.Bu nedenle hazır yazının ortalarına gelmemişken, internetten başka bir  3d araç modeli seçmenizde yarar olacaktır.Evet sahnemizi oluşturduk.Bu bölümde artık yapacağımız bir işlem kalmadı.Şimdi kodlarımızı yazmaya başlayabiliriz.

Kodlarımızı yazmaya başlayalım.

Evet öncelikle Project penceresinde yeni bir C# Script dosyası oluşturuyoruz.Daha sonra bu script dosyasına yeni bir isim veriyoruz ve editör yardımı ile bu dosyamızı açıyoruz.

public Transform AracGovdesi;
public Vector3 HavaliSuspansiyon;
public float SuspansiyonHizi;
public AudioSource Ses;
public AudioClip SuspansiyonSesi;

İlk olarak projemizde kullanacağımız değişkenlerimizi oluşturmaya başlayalım.İlk satırda Transform değişkeni oluşturuyoruz.Bu değişkende, aracımızın gövdesinin transform bilgilerini kontrol edeceğiz.İkinci satırda Vector3 değişkeni oluşturuyoruz.Bu değişkende ise, aracımızın süspansiyon yüksekliğine göre değişecek pozisyonunu kontrol edeceğiz.

Üçüncü satırda float türünde bir değişken oluşturuyoruz.Bu değişkende, havalı süspansiyon sisteminin hızını kontrol edeceğiz.Dördüncü satırda AudioSource değişkeni oluşturuyoruz.Bu değişken ile, AudioSource bileşenini kontrol edeceğiz.Son satırda ise, AudioClip değişkeni oluşturuyoruz.Bu değişkende ise, süspansiyonlardan çıkacak sesi kontrol edeceğiz.

[Header("Süspansiyon Seviyeleri")] 
public float SuspansiyonSeviyesi;
public float Asama1;
public float Asama2;
public float Asama3;
public bool SuspansiyonAktif;

Evet değişkenlerimizi oluşturmaya devam ediyoruz.İlk satırda, daha önceki yazılarımda görmediğiniz bir kod bulunuyor.Header kodu ile, Inspector penceresinde bulunan bölümlere başlık verebiliyorsunuz.Böylece uzun script dosyalarında değişkenlerimizi gruplandırarak, daha temiz ve düzenli bir görünüm elde edebiliyoruz.İkinci satırda, float türünde bir değişken tanımlıyoruz.

Bu değişkenle, aracımızın o anki süspansiyon seviyesini kontrol edeceğiz.Üçüncü ve beşinci satırlar arasında yine float türünde değişkenler oluşturuyoruz.Bu değişkenler, ise, havalı süspansiyon seviyelerini belirlemek için kullanacağız.Ben üç “3” tane seviye oluşturdum.Ancak siz daha az yada daha fazla seviye oluşturabilirsiniz.Son satırda ise bool türünde bir değişken oluşturuyoruz.Bu değişkenle, süspansiyonları aktif/pasif hale getirebileceğiz.

[Header("Süspansiyon Çiftleri")] 
public Vector3 AktifGrup;
public Vector3 AktifAci;
public float SuspansiyonAcisi;
public float OnSuspansiyonlar;
public float ArkaSuspansiyonlar;
public float SagSuspansiyonlar;
public float SolSuspansiyonlar;
public bool CiftlerAktif;

Değişkenlerimizi oluşturmaya devam ediyoruz.İlk satırda yeni bir başlık oluşturuyoruz.İkinci satırda Vector3 değişkeni oluşturuyoruz.Bu değişkenle, aktif süspansiyon grubunun pozisyon değerlerini kontrol edeceğiz.İkinci satırda yine Vector3 değişkeni oluşturuyoruz.Bu değişkenle ise, aktif süspansiyon grubunun açısını kontrol edeceğiz.

Dördüncü ve sekizinci satırlar arasında float türünde değişkenler oluşturuyoruz.Bu değişkenler ile, aracımızın birbirinden bağımsız dört “4” süspansiyonunu kontrol edeceğiz.Böylece belirlediğimiz açılarda ve yüksekliklerde aracımızın süspansiyonlarını ayarlayabileceğiz.Son satırda ise, bool türünde bir değişken oluşturuyoruz.Bu değişkenle ise, süspansiyon gruplarını aktif/pasif hale getirebileceğiz.

Havalı süspansiyon sistemini oluşturmaya başlayalım.

Evet bu aşamaya kadar script dosyamızda sadece, bize gerekecek değişkenleri oluşturduk.Şimdi ise, bu değişkenlere değerlerini tanımlamaya başlayabiliriz.

AracGovdesi = GameObject.FindWithTag("arac_govdesi").transform;
Ses = GetComponent<AudioSource>();
SuspansiyonHizi = 1f;
Asama1 = -2.5f;
Asama2 = 2f;
Asama3 = 5f;
SuspansiyonAktif = false;
OnSuspansiyonlar = -15f;
ArkaSuspansiyonlar = 15f;
SagSuspansiyonlar = -2.5f;
SolSuspansiyonlar = 15f;
CiftlerAktif = false;

Evet şimdi bu kodları start() fonksiyonumuzun içerisine yazıyoruz.İlk satırda değişkenimize, etiketi “arac_govdesi” olan nesnemizin transform değerlerini tanımlıyoruz.İkinci satırda değişkenimize, script dosyamızın ekli olduğu nesnenin AudioSource bileşenini tanımlıyoruz.Üçüncü satırda değişkenimize, bir değer veriyoruz.Bu değer, süspansiyonların hızını belirleyecektir.

Dördüncü ve beşinci satılar arasında ise, değişkenlerimize farklı değerler veriyoruz.Dördüncü yani “Asama1” değişkeni, aracımızın en alçak konumdaki değerini temsil ederken, altıncı yani “Asama3” değişkeni aracımızın en yüksek konumdaki değerini temsil edecektir.Yedinci satırda ise, bool türündeki değişkenimizin değerini false olarak belirliyoruz.

Sekizinci ve on birinci satırlar arasında ise, değişkenlerimize yine birer değer veriyoruz.Ancak bu değişkenler, aracımızın süspansiyonlarına açı verecek değişkenler olduğu için verdiğiniz değerleri deneme yanılma ile bulmanız gerekiyor.Son satırda ise, bool türündeki değişkenimizin değerini false olarak belirliyoruz.Böylece projemizi başlattığımız zaman, süspansiyonlar kilitli oluyor.

void SuspansiyonKontrolu(float Asama, bool Durum) {
   HavaliSuspansiyon = new Vector3(AracGovdesi.localPosition.x,  AracGovdesi.localPosition.y, Asama);
   if (Durum) {
      AracGovdesi.localPosition = Vector3.Lerp(AracGovdesi.localPosition, HavaliSuspansiyon, SuspansiyonHizi * Time.deltaTime);
   }
}

Evet şimdi yeni bir fonksiyon oluşturuyoruz.Bu fonksiyonumuzun amacı, aracımızın süspansiyonlarını kontrol etmek içindir.Oluşturduğumuz fonksiyon, parametreli bir fonksiyon olması gerekiyor ki istediğimiz gibi kontrol edebilelim.İlk satıra bakacak olursak, parantez içerisinde bir adet float bir adette bool türünde değişkenler görüyoruz.

İkinci satırda Vector3 değişkenimizin değerine, yeni bir Vector3 değişkeni oluşturarak eşitliyoruz.Parantez içerisine bakacak olursak ilk bölümde, “AracGovdesi” değişkenimizin x pozisyonu, ikinci bölümde “AracGovdesi” değişkenimizin y pozisyonu, üçüncü ve son bölümde ise, float türündeki değişkenimiz “Asama” bulunuyor.Burada dikkat etmemiz gereken bir yer bulunuyor.

Gördüğünüz gibi araç gövdemizin transform değerini çekmek için, position değilde localPosition olarak yazıyoruz.Bunun nedeni, hierarşik olarak araç gövdemizin başka bir nesnenin (parent) alt nesnesi (child) olmasındn kaynaklanıyor.Eğer biz position olarak yazsaydık, transform bilgileri çok farklı ve yanlış değerler olacaktı.Bu noktaya dikkat etmeniz önem arz ediyor.

Üçüncü satırda, yeni bir koşul oluşturuyoruz.Eğer bool değişkenimizin değeri true ise, koşulumuz aktif oluyor.Dördüncü satırda ise, “AracGovdesi” değişkenimizin localPosition değerini Lerp fonksiyonunu kullanarak güncelliyoruz.Burada Vector3.Lerp fonksiyonunu kullanmamızın nedeni, süspansiyon yüksekliğinin birden değişmemesi, yani yavaşça ve yumuşak bir şekilde hedef noktaya ilerlemesi içindir.

void SuspansiyonKombinleri(Vector3 SuspansiyonGrubu, Vector3 SuspansiyonAcisi, float Aci, bool Durum) {
   AktifGrup = new Vector3(AracGovdesi.localPosition.x,  AracGovdesi.localPosition.y, Aci);
   if (Durum) {
      AracGovdesi.localPosition = Vector3.Lerp(AracGovdesi.localPosition, SuspansiyonGrubu, SuspansiyonHizi * Time.deltaTime);
      AracGovdesi.localRotation = Quaternion.Lerp(AracGovdesi.localRotation, Quaternion.Euler(SuspansiyonAcisi), 0.5f * Time.deltaTime);
   }
   else {
      AracGovdesi.localRotation = Quaternion.Lerp(AracGovdesi.localRotation, Quaternion.Euler(0, 0, 0), SuspansiyonHizi * Time.deltaTime);
   }
}

Evet şimdi yeni bir fonksiyon daha oluşturuyoruz.Bu fonksiyonda ilk fonksiyonumuz gibi parametre bulunduruyor.Bu fonksiyonumuzun amacı ise ilkinden farklı olarak, süspansiyonlarımıza açı vermektir.Yani, sağa/sola yada ileri/geri aracımızın gövdesine açı verebileceğiz.Aldığı parametreler ise iki adet Vector3, bir adet float ve bir adette bool türünde değişkenlerdir.

İkinci satıra bakacak olursak, “AktifGrup” değişkenimize yeni bir değer tanımlıyoruz.İlk fonksiyondan farklı olarak, burada üçüncü bölümde açı değerimiz bulunuyor.Üçüncü satırda yeni bir koşul oluşturuyoruz.Eğer bool değişkenimizin değeri true ise, koşulumuz aktif oluyor.Dördüncü satırda, “AracGovdesi” değişkenimizin localPosition değerini Lerp fonksiyonunu kullanarak değiştiriyoruz.

Beşinci satırda ise, “AracGovdesi” değişkenimizin localRotation değerini Lerp fonksiyonunu kullanarak değiştiriyoruz.Ancak bu sefer, Quaternion.Lerp fonksiyonundan yardım alıyoruz.Çünkü değiştirdiğimiz değer, rotation bölümün kapsıyor.Koşulumuzun else bölümünde ise, “AracGovdesi” değişkenimizin localRotation değerini sıfırlıyoruz.Bunu yapmak içinde, Quaternion.Euler fonksiyonumuzun aldığı eksen değerlerini sıfırlıyoruz.

Süspansiyon sistemini kontrol edelim.

Evet bu aşamaya kadar, havalı süspansiyon sistemimizin alt yapısını oluşturduk.Artık bu sistemi nasıl kontrol edeceğimize gelebiliriz.Bunun için klavyede önceden belirlediğimiz tuşları kullanacağız.Bunu yapmak için switchcase yada ifelse yapısını kullanabiliriz.Ben anlamanız daha kolay olsun diye, ifelse yapısını tercih ettim.Toplamda yedi “7” adet tuş kullanacağımız ve birbirlerine benzer işlevleri olacağı için, sadece belirli tuşları ve kod bloklarını anlatacağım.

Diğer türlü yazı çok uzayacak ve tekrar düşen kod blokları göreceksiniz.Bunu baştan belirtmekte yarar var diye düşünüyorum.Şimdi tuş gruplarına bir bakalım.Genel olarak tuşları üç “3” gruba ayırdım.İlk grup (Q, W, E) yani aracımızın süspansiyonlarının yüksekliğini ayarlayan tuşları kapsıyor.İkinci grup (A, S) yani aracımızın süspansiyonlarının ileri-geri açısını ayarlayan tuşları kapsıyor.Üçüncü ve son grup ise (Z, X) yani aracımızın süspansiyonlarının sağa-sola açısını ayarlayan tuşları kapsıyor.

if (Input.GetKeyUp(KeyCode.Q)) {
   SuspansiyonAktif = true;
   CiftlerAktif = false;
   SuspansiyonSeviyesi = Asama1;
   if (!Ses.isPlaying) {
      Ses.clip = SuspansiyonSesi;
      Ses.PlayOneShot(SuspansiyonSesi);
   }
}

Evet ilk grubumuz ile başlıyoruz.Bu kodları update() fonksiyonumuzun içerisine yazıyoruz.İlk satırda yeni bir koşul oluşturuyoruz.Eğer klavyeden “Q” tuşuna basarsak koşulumuz aktif oluyor.İkinci satırda “SuspansiyonAktif ” değişkenimizin değerini, true olarak değiştiriyoruz.Üçüncü satırda “CiftlerAktif ” değişkenimizin değerini, true olarak değiştiriyoruz.

Dördüncü satırda ise, “SuspansiyonSeviyesi” değişkenimizin değerini “Asama1” değişkenimizin değerine eşitliyoruz.Beşinci satırda yine bir koşul oluşturuyoruz.Eğer herhangi bir ses dosyası çalmıyor ise, koşulumuz aktif oluyor.Altıncı satırda “Ses” değişkenimizin clip özelliğine “SuspansiyonSesi” değişkeninde tanımlı sesi eşitliyoruz.Yedinci satırda ise, PlayOneShot fonksiyonu yardımı ile, bu sesi bir kere çalıyoruz.

if (Input.GetKeyUp(KeyCode.A)) {
   CiftlerAktif = !CiftlerAktif;
   SuspansiyonAcisi = ArkaSuspansiyonlar;
   AktifAci = new Vector3(-5f, 0, 0);
   if (!Ses.isPlaying) {
      Ses.clip = SuspansiyonSesi;
      Ses.PlayOneShot(SuspansiyonSesi);
   }
}

İkinci grubumuza geçecek olursak, yine bu kodları update() fonksiyonumuzun devamına yazıyoruz.İlk satırda yeni bir koşul oluşturuyoruz.Eğer klavyeden “A” tuşuna basarsak koşulumuz aktif oluyor.İkinci satırda “CiftlerAktif ” değişkeniminiz değerine “!CiftlerAktif ” değişkenimizin değerine eşitliyoruz.Ancak burada bir ufak nokta var.Eğer değişkenimizin değeri, true ise false olacaktır.Tam tersi durumda ise, true olacaktır.

Üçüncü satırda, “SuspansiyonAcisi” değişkenimizin değerini, “ArkaSuspansiyonlar” değişkenimizin değerine eşitliyoruz.Dördüncü satırda, “AktifAci” değişkenimizin değerine, yeni bir Vector3 tanımlıyoruz.Böylece aracımız x ekseninde “-5” değerinde açı alıyor.Beşinci satırdan itibaren yukarıda anlattığım gibi aynı olaylar meydana geliyor.Tekrar tekrar anlatmaya gerek yok diye düşünüyorum.

if (Input.GetKeyUp(KeyCode.Z)) {
   CiftlerAktif = !CiftlerAktif;
   SuspansiyonAcisi = SagSuspansiyonlar;
   AktifAci = new Vector3(0, 10f, 0);
   if (!Ses.isPlaying) {
      Ses.clip = SuspansiyonSesi;
      Ses.PlayOneShot(SuspansiyonSesi);
   }
}

Üçüncü ve son grubumuza geçecek olursak, yine bu kodları update() fonksiyonumuzun devamına yazıyoruz.İlk satırda yeni bir koşul oluşturuyoruz.Eğer klavyeden “Z” tuşuna basarsak koşulumuz aktif oluyor.İkinci satırda “CiftlerAktif ” değişkeniminiz değerine “!CiftlerAktif ” değişkenimizin değerine eşitliyoruz.Yukarıda anlattığım gibi, her “Z” tuşuna basışta “CiftlerAktif ” değişkenimizin aldığı değer (true, false) değişekecektir.

Üçüncü satırda, “SuspansiyonAcisi” değişkenimizin değerini, “SagSuspansiyonlar” değişkenimizin değerine eşitliyoruz.Dördüncü satırda, “AktifAci” değişkenimizin değerine, yeni bir Vector3 tanımlıyoruz.Böylece aracımız y ekseninde “10” değerinde açı alıyor.Beşinci satırdan itibaren ses bölümü yine yukarıdaki kod bloklarından bir farkı olmadığı için atlıyorum.

SuspansiyonKontrolu(SuspansiyonSeviyesi, SuspansiyonAktif);
SuspansiyonKombinleri(AktifGrup, AktifAci, SuspansiyonAcisi, CiftlerAktif);

Evet son olarak, yazmış olduğumuz iki fonksiyonumuzu update() fonksiyonumuzun içerisine ekliyoruz.Böylece script dosyamız tamamlanmış oluyor.Şimdi Hierarchy penceresinde yeni bir boş nesne oluşturuyoruz.Daha sonra bu boş nesneyi seçiyoruz ve Inspector penceresinden AudioSource bileşenini ekliyoruz.Sonra C# Script dosyamızı bu boş nesnemizin üzerine sürükleyerek bırakıyoruz.Artık test etmeye hazırız.Evet bu projemizin de sonuna geldik.Bir sonraki yazıda görüşmek üzere..

Unity-Havalı-Süspansiyon-Yapımı-How-Does-Air-Suspension-Work