
Unity’de OverlapSphere Kullanımı
Merhaba, bir önceki dersimizde Unity ile raycast ışınlarının konumu ve açısını değiştirmeyi öğrenmiştik.Bu sayede yapmış olduğunuz projelerde raycast ışınlarının başlangıç pozisyonlarını değiştirerek, ilgili mekaniklerin daha kararlı çalışmalarını sağlayabilirsiniz.Bugünkü dersimizde ise Unity‘de OverlapSphere kullanımını öğreneceğiz.Kısaca OverlapSphere, bir küre içerisinde çarpışma olup/olmadığını anlamak için kullanılıyor.Birazdan daha detaylı olarak anlatacağım.Şimdi yeni bir projesi oluşturalım ve dersimize başlayalım.
Sahnemizi hazırlamaya başlayalım.
Evet ilk olarak bu projedeki senaryomuza bir bakalım.360 derece bir alan içerisinde çarpışma kontrolü yapacağımız için, sahnemizde bir oyuncumuz olacak ve üzerimize gelen düşmanlar bu alan içerisine girer girmez oyuncumuzun açısı düşmana bakacak şekilde güncellenecek.Böylece hangi açıdan geldiğine bakılmaksınız, düşmanı tespit edebileceğiz.
Şimdi ilk olarak sahnemize bir Plane nesnesi ekliyoruz.Bu bizim zeminimizi oluşturacak.Daha sonra Inspector penceresinden Plane nesnemizin boyutlarını arttırıyoruz.Çünkü geniş bir alan, sonuçları görebilmek için daha iyi olacaktır.Daha sonra oyuncumuzu sahnemize ekliyoruz.Ben internetten bulduğum 3d bir modeli tercih ettim.Ancak Unity‘de bulunan hazır nesneleri de kullanabilirsiniz.Oyuncu nesnemize yeni bir etiket veriyoruz.
Daha sonra nesnemizi seçiyoruz ve Inspector penceresinde en altta bulunan “Add Component” butonuna basarak yeni bir Sphere Collider bileşeni ekliyoruz.Bileşeni ekledikten sonra hemen altında yer alan “Edit Collider” butonuna basıyoruz ve Scene penceresinde Sphere Collider çapını değiştiriyoruz.Sonra düşmanların bu alandan içeriye girebilmeleri için, “Is Trigger” özelliğini aktif hale getiriyoruz.
Böylece bir sonraki düşman rastgele bir noktada spawn olup, üzerimize gelebilecektir.Yalnız bu noktada bir uyarı yapmam gerekiyor.Bu yazının konusu OverlapSphere kullanımı öğrenmek olduğu için, sadece bununla ilgili kodları göreceğiz.Yani konumuz dışındaki mekanikleri anlatmayacağım.Aksi takdirde yazımızın asıl amacından sapmış olacağız.Şimdi devam edebiliriz.
Şimdi düşmanımızı sahnemize ekliyoruz.Yine ben, internetten bulduğum 3d bir modeli tercih ettim.Ancak Unity‘de bulunan hazır nesneleri de kullanabilirsiniz.Burada dikkat etmemiz gereken bazı noktalar var.İlk olarak nesnemize Inspector penceresindeki “Add Component” butonuna basarak yeni bir Rigidbody bileşeni ekliyoruz.Bu bileşeni eklemezsek, oyuncumuza ekleyeceğimiz tetikleyici kodları çalışmayacaktır.Daha sonra yine Inspector penceresinde yeni bir etiket ve layer oluşturuyoruz.
Layer yani katman bu noktada önemli, çünkü OverlapSphere etiketlere göre ayırt etme yeteneğine sahip değildir.Bu yüzden katmana göre ayırt etmemiz gerekiyor.Kod kısmında bunu daha detaylı anlatacağım.Yukarıdaki resimde görüldüğü gibi, Inspector penceresinde birde Box Collider bileşenini görüyoruz.Bunun nedeni ise, seçtiğim modelin merkez noktasının farklı olması ve modeli bir Cube nesnesini alt nesnesi (child object) olarak kullanmamdır.Şimdi Hierarchy penceresindeki bu nesnemizi sürükleyerek Project penceresine bırakıyoruz.Böylece daha sonra kullanmak üzere Prefab nesnemiz hazır olmuş oluyor.
Kodlarımızı yazmaya başlayalım.
Şimdi Project penceresinde yeni bir C# script dosyası oluşturuyoruz.Bu script dosyasını belirlediğimiz alan içerisinde çarpışma olup olmadığını tespit etmek ve oyuncumuzun açısını değiştirmek için kullanacağız.Şimdi dosyamızı editör yardımı ile açarak kodlarımızı yazmaya başlıyoruz.
public GameObject Dusman; public Collider[] CemberIcindekiler; public float Yaricap; public float DonusHizi; public LayerMask Katman; private Vector3 KendiPozisyonumuz;
İlk olarak script dosyamızda kullanacağımız değişkenleri oluşturmaya başlıyoruz.İlk satırda bir GameObject oluşturuyoruz.Bunu prefab dosyamızı kontrol etmek için kullanacağız.İkinci satırda bir Collider dizisi oluşturuyoruz.Bu sayede tespit ettiğimiz çarpışmaları bir dizide tutabileceğiz.Üçüncü ve dördüncü satırlarda float türünde değişkenler oluşturuyoruz.
Üçüncü satırdaki değişken çarpışma alanının çapını kontrol ederken, dördüncü satırdaki değişken oyuncumuzun etrafındaki dönüş hızını ayarlıyor.Beşinci satırda bir LayerMask oluşturuyoruz.Bunu düşmanları ayırt etmek için kullanacağız.Son satırda ise bir Vector3 yapısı oluşturuyoruz.Bu yapı ile belirleyeceğimiz alanın başlangıç konumunu kontrol edebileceğiz.
Nesne tespiti için fonksiyonumuzu oluşturalım.
public void DusmanBul(Vector3 merkezNokta, float Cap) { CemberIcindekiler = Physics.OverlapSphere(merkezNokta, Cap, Katman); ... }
Evet şimdi yeni bir fonksiyon oluşturuyoruz.Bu fonksiyonumuzda iki adet parametremiz bulunuyor.İlki bir Vector3 yapısı ikinci ise, float türünde bir değişken oluyor.Bunları oluşturacağımız alanın merkez noktasını bulmak ve bu alanın çapını belirlemek için kullanacağız.İkinci satırda “CemberIcindekiler” dizisine, OverlapSphere fonksiyonu ile bulduğumuz çarpışmaları ekliyoruz.Parantez içerisine bakacak olursak burada kullandığımız üç parametreyi görüyoruz.
İlk parametremiz kullanacağımız alanın merkez noktası, ikinci parametremiz kullanacağımız alanın çapı ve son parametremiz ise bu alandaki nesneleri ayırt etmemiz için bir katman.Az öncede bahsettiğim gibi, buradaki üçüncü parametre önemlidir.Çünkü belirlediğimiz alanın içerisine giren her nesneyi tespit etmek istemeyiz.Bunlar arasında asıl istediğimiz nesneleri tespit etmek için layer kullanıyoruz.Aslında kullanmak zorundayız.Çünkü etiketleri ayırt etme yeteneği bulunmuyor.
for (var i = 0; i < CemberIcindekiler.Length; i++) { if (CemberIcindekiler.Length > 0) { Quaternion yeniAci = Quaternion.LookRotation(transform.position - CemberIcindekiler[CemberIcindekiler.Length-1].transform.position); yeniAci.x = 0; yeniAci.z = 0; transform.rotation = Quaternion.RotateTowards(transform.rotation, yeniAci, DonusHizi * Time.deltaTime); } }
Fonksiyonumuzun içerisine bu kodları yazıyoruz.İlk satırda yeni bir for döngüsü oluşturuyoruz.Bunu bir while yada foreach döngüsü ile de yapabilirsiniz.Ben bilinmeyen bir nedenden ötürü bu döngüyü kullandım.Döngümüzün koşuluna bakacak olursak, “CemberIcindekiler” dizisinin eleman sayısından küçükse döngümüzü devam ettiriyoruz.Yani bu alan içine giren her bir yeni nesnede döngünün devam edeceği anlamına geliyor.İkinci satırda yeni bir koşul oluşturuyoruz.
Eğer “CemberIcindekiler” dizisinin eleman sayısı, sıfırdan büyükse koşulumuz aktif oluyor.Üçüncü satırda bir Quaternion yapısı oluşturuyoruz.LookRotation fonksiyonunu kullanarak oyuncu pozisyonunu, “CemberIcindekiler” dizisine eklenen son nesnenin pozisyonundan çıkartıyoruz.Bu bize oyuncumuzun düşmana dönmesi için gereken açıyı veriyor.
Dördüncü ve beşinci satırlarda hesapladığımız açının x ve y değerlerini sıfırlıyoruz.Bunu yapmamızın nedeni ise, oyuncumuzun sadece y ekseninde dönmesi gerektiği içindir.Altıncı satırda ise oyuncumuzun rotation değerlerini değiştiriyoruz.Bunu yaparken, RotateTowards fonksiyonundan yararlanıyoruz.Parentez içerisine bakacak olursak, oyuncumuzun rotation değerleri, hesapladığımız “yeniAci” değeri ve “DonusHizi” değişkenimiz yer alıyor.Bu fonksiyon sayesinden belirlediğimiz hızlarda oyuncumuz alan içerisine giren son düşmana doğru dönebiliyor.
Düşman spawn sistemi için fonksiyonumuzu oluşturalım.
public IEnumerator SiradakiDusman(float Sure) { yield return new WaitForSeconds(Sure); Instantiate(Dusman, new Vector3(Random.Range(0, 5), Random.Range(0, 5), 0), Quaternion.identity); }
Alan içerisine giren düşmandan sonra yeni düşmanın hemen spawn olmaması için IEnumerator metodunu kullanıyoruz.Burada bir tane float türünde parametremiz bulunuyor.Bununla düşmanlar arasındaki spawn süresini kontrol edebileceğiz.İkinci satırda bir sonraki kareye belirlediğimiz süre kadar bekle diyoruz.Bunu WaitForSeconds fonksiyonu ile yapıyoruz.Üçüncü satırda Instantiate fonksiyonu ile yeni bir düşman nesnesi oluşturuyoruz.
Parantez içerisine bakacak olursak, ilk bölümde Prefab nesnemiz yer alıyor.İkinci bölümde spawn nesnelerin konumu yer alıyor.Burada yeni bir Vector3 yapısı oluşturuyoruz.Random.Range fonksiyonu ile spawn nesnelerin x ve y eksenlerinin pozisyonlarını sınırlandırmış oluyoruz.Siz bu değeri kendinize göre arttırabilir yada azaltabilirsiniz.Z eksenini ise sıfır “0” değerini vererek değiştirmemiş oluyoruz.Üçüncü ve son bölümde ise spawn nesnemizin kendi rotasyon değerlerini kullanmasını sağlıyoruz.
public void OnTriggerEnter(Collider kontrol) { if (kontrol.tag == "Respawn") { StartCoroutine(SiradakiDusman(2f)); } }
Şimdi yeni bir tetikleyici fonksiyonu oluşturuyoruz.Burada OnTriggerEnter fonksiyonunu kullanacağız.Çünkü belirlediğimiz alana düşman nesnemizin bir kez giriş yapması yeterli olacaktır.İkinci satırda yeni bir koşul oluşturuyoruz.Eğer çarpışmanın olduğu nesnenin etiketi “Respawn” ise koşulumuz aktif oluyor.Üçüncü satırda ise StartCoroutine ile fonksiyonumuzu çağırıyoruz.Böylece belirlediğimiz zaman içerisinde yeni düşman nesnemiz spawn oluyor.
void OnDrawGizmos() { Gizmos.color = Color.blue; Gizmos.DrawWireSphere(KendiPozisyonumuz, Yaricap); Gizmos.color = Color.red; Gizmos.DrawWireSphere(KendiPozisyonumuz, Yaricap * 3); }
Şimdi yeni bir OnDrawGizmos fonksiyonu oluşturuyoruz.Bu fonksiyon sayesinde Scene penceresinde belirlediğimiz çarpışma alanını ve düşmanların spawn alanını görebileceğiz.Kısaca bu fonksiyonun amacı ekrana gizmos çizmek için kullanılıyor.İkinci satıra bakacak olursak, çizim rengini belirliyoruz.Üçüncü satırda DrawWireSphere fonksiyonu ile bir küre çiziyoruz.Parantez içerisinde ise iki parametremiz yer alıyor.İlk parametremiz küremizin başlangıç konumu, ikinci parametremiz ise küremizin çapını kontrol ediyor.
Sahnemizde ikinci bir gizmos çizmek için yeni bir fonksiyon oluşturmuyoruz.Bunun yerine aynı fonksiyonumuzun devamına yeni bir tane oluşturuyoruz.Dördüncü satırda ikinci çizim için yeni bir renk tanımlıyoruz.Beşinci satırda tekrar DrawWireSphere fonksiyonu ile bir küre çiziyoruz.Parantez içerisindeki parametreler yine aynı oluyor.Ancak burada ikinci küremiz düşmanların spawn noktasını temsil ettiği için, “Yaricap” değişkenimizin değerini belirlediğimiz bir sayı ile çarpıyoruz.
Bu resimde görüldüğü gibi yeşil alan, tetikleyici noktasını oluşturuyor.Yani yeni bir düşmanın oluşmasını sağlıyor.Mavi alan yazımızın konusunu yani, küre içerisinde çarpışma tespit noktasını oluşturuyor.Kırmızı alan ise, düşmanların spawn noktasını oluşturuyor.
Instantiate(Dusman, new Vector3(Random.Range(0, 5), Random.Range(0, 5), 0), Quaternion.identity);
Şimdi projemizi başlattığımızda ilk düşman nesnemizin spawn olabilmesi için, bu kodu start() fonksiyonumuzun içerisine yazıyoruz.
KendiPozisyonumuz = new Vector3 (transform.position.x, 0, transform.position.z); DusmanBul(KendiPozisyonumuz, Yaricap);
Bu kodları ise update() fonksiyonumuzun içerisine yazıyoruz.İlk satırda “KendiPozisyonumuz” vector3 yapısına oyuncu nesnesinin x pozisyonu ve z pozisyonunu tanımlıyoruz.Y pozisyonunu ise sıfır “0” değerine sabitliyoruz.İkinci satırda ise az önce oluşturduğumuz “DusmanBul” fonksiyonunu çağırıyoruz.Parantez içerisine ilgili parametrelerini ekliyoruz.
Düşmanlar için kodlarımızı yazmaya başlayalım.
Şimdi Project penceresinde yeni bir C# script dosyası daha oluşturuyoruz.Bu script dosyasını düşman nesnelerin oyuncu nesnemize doğru gelmesini sağlamak için kullanacağız.Şimdi script dosyamızı editör yardımı ile açarak kodlarımızı yazmaya başlıyoruz.
public GameObject Hedef; public float Hiz;
İlk olarak değişkenlerimizi oluşturuyoruz.İlk satırda bir GameObject oluşturuyoruz.Bunu düşman nesnelere hedeflerini belirtmek için kullanacağız.İkinci satırda ise float türünde bir değişken oluşturuyoruz.Bu değişkeni ise, düşman nesnelerin hareket hızını kontrol etmek için kullanacağız.
Hedef = GameObject.FindWithTag("Player");
Bu kodu start() fonksiyonunun içerisine yazıyoruz.”Hedef” GameObject nesnemize etiketi “Player” olan nesneyi tanımlıyoruz.
if (Vector3.Distance(transform.position, Hedef.transform.position) < 5) { Destroy(this.gameObject); }else { transform.position = Vector3.MoveTowards(transform.position, Hedef.transform.position, Hiz * Time.deltaTime); transform.LookAt(Hedef.transform); }
Şimdi update() fonksiyonumuzun içerisine bu kodları yazıyoruz.İlk satırda yeni bir koşul oluşturuyoruz.Eğer düşman nesnesi ile oyuncu nesne arasındaki uzaklık beşten “5” küçük ise koşulumuz aktif oluyor.Bunu hesaplamak içinde Vector3.Distance fonksiyonunu kullanıyoruz.İkinci satırda Destroy fonksiyonu ile düşman nesnemizi siliyoruz.Eğer koşulumuz aktif değilse, yani false konumunda ise bu sefer else bloğuna gidiyoruz.
Dördüncü satırda düşman nesnemizin pozisyonunu MoveTowards fonksiyonunu kullanarak oyuncu nesnemize doğru ilerletiyoruz.Parantez içerisinde ise kendi pozisyonu, oyuncu pozisyonu ve hareket hızı bulunuyor.Beşinci satıra bakacak olursak, LookAt fonksiyonunu görüyoruz.Bu fonksiyon ile oyuncu pozisyonuna doğru düşman nesnemizi döndürüyoruz.Yani açısını hedefe doğru ayarlıyoruz.
Evet bu projemizinde sonuna geldik.Şimdi oluşturmuş olduğumuz C# Script dosyalarını ilgili nesnelere ekleyelim.İlk script dosyamızı sürükleyerek, oyuncu nesnemizin üzerine bırakıyoruz.Daha sonra Inspector penceresinde “Dusman” bölümüne Hierarchy penceresindeki Prefab nesnemizi ekliyoruz.”YariCap”, “DonusHizi” bölümlerine istediğimiz değerleri veriyoruz.”Katman” bölümünde ise düşman nesnelerimiz için oluşturduğumuz katmanı seçiyoruz.Daha sonra ikinci script dosyamızı Prefab nesnemizin üzerine sürükleyerek bırakıyoruz.Burada, “Hiz” değişkenimize bir değer veriyoruz ve kaydediyoruz.Evet şimdi test edebiliriz.Bir sonraki yazıda görüşmek üzere…