Unity’de Silaha Geri Tepme Eklemek (Recoil System)
Merhaba, bir önceki yazımızda Unity‘de duvar parçalamayı öğrenmiştik.İstediğimiz herhangi bir nesneyi eğer model yapısı izin veriyorsa, parçalayabiliyorduk.Bu dersimizde ise, Unity ile silaha geri tepme mekaniği yapacağız.Böylece yaptığımız projelerdeki silahlarda, daha gerçekçi bir atış hissi oluşturabileceğiz.Şimdi vakit kaybetmeden yeni bir proje oluşturalım ve dersimize başlayalım.
Sahnemizi hazırlamaya başlayalım.
Bu projede kullanacağımız senaryoya bakalım.Bir silahımız olacak ve fare yardımı ile ateş edeceğiz.Tabi bu silahımızından mermi de çıkartacağız.Ancak bu projede amacımız belli olduğu için, biz diğer mekaniklerden çok silahımızın geri tepmesine odaklanacağız.Şimdi projede kullanacağımız silahı Unity‘de bulunan hazır nesnelerden de yapabiliriz.Yada internetten bulduğumuz silah modellerini de kullanabiliriz.Bu noktada tercih size kalmış.Ben internetten bulduğum bir silah modelini kullanacağım.
Yapacağımız işlemler bir farklılık göstermeyecektir.Bunu baştan belirteyim.Eğer model kullanmayı tercih ettiyseniz, önce silahımızı projemize dahil ediyoruz.Daha sonra bu silah nesnemizi sahnemize ekliyoruz.Şimdi Hierarchy penceresinde yeni bir boş nesne oluşturuyoruz.Oluşturduğumuz bu boş nesnenin üzerine, silah nesnemizi sürükleyip bırakıyoruz.Böylece silah nesnemiz, boş nesnenin çocuk “child” nesnesi oldu.Bu şekilde hiyerarşik bir düzen yapmamızın bir nedeni var.Yeri geldiği zaman değineceğim.
Daha sonra silahımızdan çıkacak merminin hangi pozisyonda oluşacağını belirlememiz gerekiyor.Bunun için silah nesnemizin içinde yeni bir Cube nesnesi oluşturuyoruz.Bu nesneyi Scene penceresinden, silahımızın ucunda yani namlusuna göre konumlandırıyoruz.Şimdi bu Cube nesnemizin Inspector penceresinden Mesh Filter, Mesh Renderer ve Box Collider bileşenlerini siliyoruz.Bunu yapmak yerine boş bir nesne ekleyip aynı şekilde yapabilirdik.Ancak istediğimiz yere hizalarken daha çok zorlanacaktık.
Bu yüzden bir Cube nesnesi kullandık ve daha sonra herhangi bir çakışmaya sebep vermemek için tüm bileşenlerini kaldırdık.Son olarak yapmamız gereken silahtan çıkacak mermiyi oluşturmak.Bunu yapmak için, yeni bir Sphere nesnesi oluşturuyoruz.Daha sonra bu nesneye Inspector penceresinden Rigidbody bileşenini ekliyoruz.Şimdi bu nesneyi Project penceresine sürükleyip bırakıyoruz.Böylece bu nesnemizi Prefab olarak kullanabileceğiz.Artık sahnemizden Sphere nesnemizi silebiliriz.Sahnemiz hazır duruma geldi.Son hali bu şekildedir.
Kodlarımızı yazmaya başlayalım.
Bu projede iki adet C# Script dosyası kullanacağız.İlk script dosyamız, silahımıza ekleyeceğimiz geri tepme mekaniğini oluştururken, ikinci script dosyamız ile de mermi mekaniğini oluşturacağız.Şimdi ilk script dosyamızı editör yardımı ile açalım ve kodlarımızı yazmaya başlayalım.
public float xEkseniMaxTepme; public float yEkseniMaxTepme; public float zEkseniMaxTepme; public float xEkseniMaxHareket; public float zEkseniMaxHareket; public float GeriTepmeHizi; private float GeriTepme;
İlk olarak değişkenlerimizi oluşturmakla başlıyoruz.Gördüğünüz gibi bütün değişkenlerimizi, float türünde oluşturuyoruz.İlk satırda, silahımızın x eksenindeki maksimum tepmesini kontrol ediyoruz.İkinci satırda, silahımızın y eksenindeki maksimum tepmesini kontrol ediyoruz.Üçüncü satırda ise, silahımızın z eksenindeki maksimum tepmesini kontrol ediyoruz.Dördüncü satırda, silahımızın x eksenindeki maksimum hareketini kontrol ediyoruz.Burada aynı eksen için iki farklı değişken oluşturmuşuz gibi algılanabilir.
Buradaki fark, bir değişkenimiz x eksenindeki rotation değerlerini kontrol ederken, diğeri x eksenindeki position değerlerini kontrol ediyor.Birazdan daha iyi anlayacağınızı düşünüyorum.Beşinci satıra bakacak olursak, silahımızın z eksenindeki maksimum hareketini kontrol ediyoruz.Son satırda oluşturduğumuz değişken ile, silahımızın geri tepme hızını kontrol ediyoruz.
xEkseniMaxTepme = -10f; yEkseniMaxTepme = -10f; zEkseniMaxTepme = -10f; xEkseniMaxHareket = 1f; zEkseniMaxHareket = 1f; GeriTepmeHizi = 1f; GeriTepme = 0;
Şimdi start() fonksiyonumuzun içerisine bu kodları yazıyoruz.Az önce oluşturmuş olduğumuz değişkenlerimize istediğimiz gibi bir değer atıyoruz.Burada kullandığınız silahın türüne ve modeline göre farklı ayarlar oluşturabilirsiniz.Böylece silahınız daha gerçekçi tepkiler verecektir.Ben rastgele değerler oluşturdum.Örneğin x, y ve z eksenleri için oluşturduğumuz değişkenler için eksi “-” değerler tanımladım.
Bu değerleri eski “-” olmadan da belirleyebilirsiniz.Bu tamamen sizin belirleyeceğiniz bir karardır.Üçüncü ve dördüncü satırlarda, silahımızın geri tepme sonucundaki hareketini ayarlıyoruz.Tavsiyem bu değişkenlerin değerlerini çok yüksek tutmamanızdan yanadır.Son satırda ise, değişkenimizin değerini sıfıra “0” eşitliyoruz.Çünkü bu değişkenin değeri, projeyi başlattığımız zaman değişkenlik gösterecek.
Silahımız için geri tepme mekaniğini oluşturalım.
public void GeriTepmeyiOlustur() { if (GeriTepme > 0) { Vector3 MaksimumHareket = new Vector3(Random.Range(transform.localPosition.x, xEkseniMaxHareket),transform.localPosition.y, Random.Range(transform.localPosition.z, zEkseniMaxHareket)); transform.localPosition = Vector3.Slerp(transform.localPosition, MaksimumHareket, GeriTepmeHizi * Time.deltaTime); Quaternion MaksimumTepme = Quaternion.Euler(Random.Range(transform.localRotation.x, xEkseniMaxTepme), Random.Range(transform.localRotation.y, yEkseniMaxTepme), Random.Range(transform.localRotation.z, zEkseniMaxTepme)); transform.localRotation = Quaternion.Slerp(transform.localRotation, MaksimumTepme, GeriTepmeHizi * Time.deltaTime); GeriTepme -= Time.deltaTime; } }
Artık değişkenlerimizi hazırladık.Şimdi onları kullanamaya başlayabiliriz.Bunun için yeni bir fonksiyon oluşturuyoruz.Bu fonksiyonda silahımızın ger tepme mekaniğini yazacağız.İkinci satırda yeni bir fonksiyon oluşturuyoruz.Eğer “GeriTepme” değişkenimizin aldığı değer, sıfırdan “0” büyükse koşulumuz doğru oluyor.Üçüncü satırda, yeni bir Vector3 değişkeni oluşturuyoruz.Bu değişkende yeni koordinat bilgilerini tutacağız.Tabi bu koordinatları rastgele oluşturacağız.
Bunun içinde Random fonksiyonundan yararlanacağız.Sadece silahımızın y eksenindeki değerini değiştirmiyoruz.Çünkü ateş ederken silahın yukarıya doğru hareket etmemesi gerekiyor.Buradaki hareketten kastım position değerleri olarak.Diğer iki eksende, değişkenlerimizde belirlediğimiz limitler doğrultusunda rastgele pozisyon değerleri oluşacaktır.Dördüncü satırda, Slerp fonksiyonu ile yeni pozisyonlara silahımızı hareket ettiriyoruz.Bu fonksiyonun aldığı parametrelere bir bakalım.
İlk olarak, nesnemizin o anki pozisyonunu çekiyoruz.İkinci olarak, az önce hesapladığımız yeni pozisyon değerlerini ekliyoruz.Son olarak, iki pozisyon arasındaki hareket hızını ekliyoruz.Tabi her karede aynı hızı elde etmek için, Time.deltaTime fonksiyonu ile çarpıyoruz.Bu aşamaya kadar, silahımızın position değerlerini değiştirdik.Şimdi ise, silahımızın rotation değerlerini değiştireceğiz.Böylece yukarıda kullanmadığımız y eksenindeki hareketini, burada rotation değerlerini değiştirerek oluşturacağız.
Beşinci satırda yeni bir Quaternion değişkeni oluşturuyoruz.Yukarıda aynı rastgele position değerleri oluşturduğumuz gibi burada da, rastgele rotation değerleri oluşturuyoruz.Yalnız bu sefer üç ekseni de dahil ediyoruz.Yine bunu yaparken, Random fonksiyonunu kullanıyoruz.Altıncı satırda ise, bu yeni rotation değerlerimizi silahımıza aktarıyoruz.Yine burada da, Slerp fonksiyonundan yararlanıyoruz.Böylece daha yumuşak geçişler elde ediyoruz.Son satırda, değişkenimizin aldığı değerini Time.deltaTime fonksiyonunu kullanarak düşürüyoruz.Bunu neden yaptığımızı birazdan anlayacaksınız.
GeriTepme = 0; Vector3 MinimumHareket = new Vector3(Random.Range(0, transform.localPosition.x),transform.localPosition.y, Random.Range(0, transform.localPosition.z)); transform.localPosition = Vector3.Slerp(transform.localPosition, MinimumHareket, GeriTepmeHizi * Time.deltaTime * 5); Quaternion MinimumTepme = Quaternion.Euler(Random.Range(0, transform.localRotation.x),Random.Range(0, transform.localRotation.y), Random.Range(0, transform.localRotation.z)); transform.localRotation = Quaternion.Slerp(transform.localRotation, MinimumTepme, GeriTepmeHizi * Time.deltaTime * 5);
farenin ilgili tuşuna tıkladıkça silahımız geri tepiyor.Buraya kadar hazırız.Ancak ateş etmeyi kestiğimiz zaman silahımızın bir önceki konumuna geri dönmesi gerekiyor.Bunu yapmak için, bu kodları koşulumuzun else kısmına yazıyoruz.Böylece geri tepme gerçekleştikten sonra silahımız, eski konumuna geri dönüyor.Şimdi ilk satıra bakacak olursak, değişkenimizin değerini sıfırlıyoruz.Çünkü fonksiyon içerisinde belirlediğimiz koşul sıfırdan büyük olduğu durumlarda çalışıyor.
Böylece faremizin ilgili tuşuna basana kadar silahımız eksi konumuna geri dönüyor.İkinci satırda, yeni bir Vector3 değişkeni oluşturuyoruz.Yukarıdaki yaptığımız işlemlerin aynısını yapıyoruz.Tek farkı Random fonksiyonunda aldığı değerler, nesnemizin kendi pozisyon değerlerini içeriyor olması.Üçüncü satırda, Slerp fonksiyonu ile nesnemizi eski konumuna getiriyoruz.Buradaki tek fark ise, silahımızın geri tepme hızı için oluşturduğumuz değeri beş “5” ile çarpmak.Buradaki değeri ben kendime göre belirledim.
Siz istediğiniz değeri yazabilirsiniz.Neden başka bir sayı ile çarpıyoruz derseniz, çünkü bir sonraki tıklama süresine kadar silahımızı mümkün olduğunca eski konumuna döndürmemiz gerekiyor.Yani bu süreyi biraz hızlandırıyoruz.Siz isterseniz bu iş için, başka bir değişken oluşturabilirsiniz.Dördüncü ve beşinci satırlarda ise durum yukarıdaki gibi aynı oluyor.Uzatmamak için tekrar girmiyorum bu kodlara.
if (Input.GetMouseButtonDown (0)) { GeriTepme += 0.01f; } GeriTepmeyiOlustur ();
Son olarak bu kodları update() fonksiyonumuzun içerisine yazıyoruz.İlk satırda yeni bir koşul oluşturuyoruz.Eğer faremizin sol tuşuna basarsak koşulumuz doğru oluyor.İkinci satırda ise değişkenimizin değerini, aldığı değer kadar arttırıyoruz.Hatırlarsanız, yeni fonksiyonumuzda bu değişkenimizin değerine göre işlem yapıyorduk.Üçüncü satırda ise, oluşturduğumuz fonksiyonumuzu çağırıyoruz.Silahımız için geri tepme mekanizması bu kadardı.İlk script dosyamızı hazırladık.
Mermilerimiz için kodlarımızı yazalım.
public GameObject Mermi; public GameObject MermiCikisi;
İlk önce kullanacağımız değişkenleri oluşturalım.İlk satırda, bir GameObject değişkeni oluşturuyoruz.Bu değişkende mermi için oluşturduğumuz Prefab nesnemizi tutacağız.İkinci satırda ise, yine bir GameObject değişkeni oluşturuyoruz.Bu değişkende ise, mermilermizin oluşacağı pozisyonların değerlerini tutacağız.
if (Input.GetMouseButtonDown (0)) { GameObject yeniMermi = Instantiate(Mermi, MermiCikisi.transform.position, MermiCikisi.transform.rotation) as GameObject; yeniMermi.GetComponent<Rigidbody> ().AddRelativeForce(Vector3.forward * 5000); Destroy (yeniMermi, 5f); }
Şimdi bu kodları update() fonksiyonumuzun içerisine yazıyoruz.İlk satırda, yeni bir koşul oluşturuyoruz.Eğer faremizin sol tuşuna basarsak, koşulumuz doğru oluyor.İkinci satırda, yeni bir GameObject değişkeni oluşturuyoruz.Bu değişkende oluşturacağımız mermi klonlarını kontrol edeceğiz.Bunu yaparken, Instantiate fonksiyonundan yararlanıyoruz.Aldığı parametrelere bakacak olursak, ilk olarak Prefab nesnemiz için oluşturduğumuz değişkeni yazıyoruz.
Daha sonra, mermilerimizin oluşacağı pozisyon için oluşturduğumuz değişkeni yazıyoruz.Son olarak ise, mermilerimizin rotasyon değerleri için oluşturduğumuz değişkeni yazıyoruz.Üçüncü satırda, klon mermizlerimizin Rigidbody bileşenine erişiyoruz.Daha sonra AddRelativeForce fonksiyonunu kullanarak belirli yönde ve hızda bir kuvvet uyguluyoruz.Dördüncü satırda ise, Destroy fonksiyonunu kullanarak oluşan mermi klonlarını belirli bir süre sonra sahnemizden siliyoruz.İkinci script dosyamızda hazır.
Evet projemizin sonuna geldik.Şimdi oluşturduğumuz script dosyalarımızı yerlerine ekleyelim.Her iki dosyayı da, silah nesnemizin üzerine sürükleyip bırakıyoruz.Daha sonra Prefab nesnemizi ve mermilerin oluşacağı pozisyon için oluşturduğumuz nesneyi belirlediğimiz yerlerine ekliyoruz.İşte bu kadar.Bir sonraki yazıda görüşmek üzere…