
Unity Kaleye Şut Çekmek (Top Fiziği)
Merhaba, bir önceki yazımızda Unity ile Raycast kullanımını öğrenmiştik.Böylelikle istediğimiz bir doğrultudan ışın atarak, çarpışma anında istediğimiz bir mekaniği gerçekleştirebiliyorduk.Bugünkü yazımızda, yine Raycast fonksiyonundan yaralanacağız.Ancak bu sefer farklı bir amaç için kullanacağız.Lafı uzatmadan yeni bir proje oluşturalım ve dersimize başlayalım.
Sahnemizin oluşturulması.
Bu yazımızda kullanacağımız senaryoyu açıklamakla başlayalım.Başlıktan anlayacağınız üzere, bir futbol topumuz olacak ve bu topa faremiz ile tıklayarak kaleye sokmaya çalışacağız.Tabi bu top, fare ile tıkladığımız açıya göre ivme kazanacak.Evet, bize gereken malzemeleri sahnemize ekleyelim.Öncelikle bir Plane nesnesi oluşturuyoruz.Bu bizim halı sahamız olacak.Daha sonra kale direklerini yapmak için, üç adet Cube nesnesi oluşturuyoruz.Bunları isterseniz bir ebeveyn altında toplayabilirsiniz.
Bunu yapmak için Hierarchy penceresinde sağ tıklayarak, Create Empty seçimini yapıyoruz ve yeni bir isim vererek kale direklerimizi üzerine sürüklüyoruz.Daha sonra bir Cube nesnesi daha oluşturuyoruz.Bu bizim duvarımız olacak.Kalemizin arkasında konumlanacağı için, topumuz boşluğa gitmeyecek.Topun duracağı yer için bir Cylinder nesnesi oluşturuyorum.Bunu siz yapmak zorunda değilsiniz.Diyelim ki yaptınız.O zaman bu silindir nesnesinin Collider bileşenini silip, yerine “Box Collider” bileşenini eklemelisiniz.
Şimdi topumuz için bir Sphere nesnesi oluşturalım.Daha sonra Inspector penceresinden bu nesneye, Rigidbody bileşenini ekliyoruz.Ayriyeten topumuzun sekmesi için, Project panelinde sağ tıklıyoruz ve Create > Physic Material seçimini yapıyoruz.Bu nesnemizi seçtiğimiz zaman sağ taraftaki pencereden, Bounciness ayarını bire “1” getiriyoruz.Şimdi bu nesnemizi sürükleyerek, Sphere nesnesinin Collider bölümde yer alan “Material” bölümüne bırakıyoruz.Son olarak bu Sphere nesnemize yeni bir etiket veriyoruz.Her zaman olduğu gibi ben sahnemde bulunan nesneleri kapladım.Bu kısım sizin tercihinize kalmış.Evet, Sahnemizin son hali bu şekildedir.
Kodlarımızın yazılması.
Öncelikle yeni bir C# Script dosyası oluşturuyoruz.Daha sonra bu script dosyasını tutup, top nesnemizin üzerine bırakıyoruz.Şimdi editör ile açarak kodlarımızı yazmaya başlayalım.
public Transform Top; public Rigidbody fizik; public float TopAgirligi; public float TopaVurusHizi; public Texture2D Fare_Imleci;
İlk olarak değişkenlerimizi yazıyoruz.İlk satırda topumuzun pozisyon değerlerini almak için bir değişken oluşturuyoruz.İkinci satırda bu topun Rigidbody bileşenine ulaşmak için bir değişken oluşturuyoruz.Üç ve dördüncü satırlarda, topumuz için kullanacağımız ağırlık ve hız değişkenlerini tanımlıyoruz.Son satırı aslında yazmak zorunda değilsiniz.Ben Game penceresinde topa tıkladığım yerin daha iyi gözükmesi için bu kodu yazdım.Kısaca fare imlecini değiştirdim.
Top = GameObject.FindWithTag ("top").transform; fizik = GameObject.FindWithTag ("top").GetComponent<Rigidbody>(); Cursor.SetCursor(FareImleci, Vector2.zero, CursorMode.Auto);
Start() fonksiyonumuzun içerisine bu kodları yazıyoruz.İlk satırda değişkenimize, etiketi “top” olan nesne eşitleniyor.İkinci satırda değişkenimize, yine etiketi “top” olan nesnenin Rigidbody bileşeni eşitleniyor.Son satırda ise, az önce değindiğim farenin imlecini değiştirmek için kodumuz bulunuyor.Dediğim gibi, bu kodu yazmak zorunda değilsiniz.
Vector3 TopaVurus(Vector3 pozisyon, float aci) { Vector3 fark = pozisyon - Top.position; float yukseklik = fark.y; fark.y = 0; float yEkseni = fark.magnitude ; float TiklamaAcisi = aci * Mathf.Deg2Rad; fark.y = yEkseni * Mathf.Tan(TiklamaAcisi); yEkseni += yukseklik / Mathf.Tan(TiklamaAcisi); float kuvvet = Mathf.Sqrt(yEkseni * Physics.gravity.magnitude / Mathf.Sin(2 * TiklamaAcisi)); return kuvvet * fark.normalized * fizik.mass; }
Şimdi topumuza tıkladığımız açı ve fizik ayarını yapacağız.Bunu için yeni bir Vector3 fonksiyonu oluşturuyoruz.Bu fonksiyonumuzda iki parametre kullanacağız.Birincisi faremizin tıkladığı pozisyon değerlerini almak için bir Vector3 değişkeni, ikincisi topa vuruş açısını hesaplamak için bir Float değişkeni.İkinci satırda, top ile tıkladığımız pozisyonun farkını alıyoruz.
Üçüncü satırda, az önce bulduğumuz farkın y eksenini alıyoruz.Dördüncü satırda, bu farkın y eksenini sıfırlıyoruz.Beşinci satırda, “yEkseni ” değişkenimize bulduğumuz farkın uzunluk bilgisini veriyoruz.Altıncı satırda, açımızı radyana dönüştürüyoruz.Radyan nedir derseniz, uzunluğa bağlı açı ölçüm birimidir.Altinci satırda, y ekseninin yükseklik açısını ayarlıyoruz.Bunu yaparken, az önce hesapladığımız radyanın tanjantını alıyoruz.
Yedinci satırda, bu sefer alçak açıları bulmak için “yEkseni ” değişkenine, “TiklamaAcisi” değişkeninin tanjantını ekliyoruz.Sekizinci satırda, tüm bu hesaplamalarımız doğrultusunda bulduğumuz sonuçlar ile bir kuvvet oluşturuyoruz.Kısaca bir karekök hesabı yapıyoruz.Ve son satırda bulmuş olduğumuz bu kuvvet değerini topumuzun kütlesi ve hesapladığımız farkı normalleştirerek döndürüyoruz.
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Input.GetMouseButton(0)){ if (Physics.Raycast (ray, out hit) && hit.transform.tag == "top") { TopaVurusHizi += Time.deltaTime; } }
Şimdi update() fonksiyonumuz içerisine bu kodları yazalım.Bu kodlara Raycast kullanımını anlattığım dersten aşinasınız diye umuyorum.İlk satırda, bir ışın oluşturuyoruz ve ana kameramızın ortasından gönderiyoruz.Tabi bu ışını faremizin pozisyonuna göre ayarlıyoruz.İkinci satırda, çarpışmaları tespit etmek için RaycastHit oluşturuyoruz.
Daha sonra bir koşul oluşturuyoruz.Eğer farenin sağ tuşuna basarsak koşulumuz doğru oluyor.Dördüncü satırda bir koşul daha oluşturuyoruz ve etiketi “top” olan nesneye tıkladığımız sürece, “TopaVurusHizi ” değişkenimizin değeri artmaya başlıyor.Bu artış hızını belirlemek için, Time.deltaTime fonksiyonunu kullanıyoruz.Böylelikle bu vuruş hızı herkeste aynı şekilde artıyor.
if (Input.GetMouseButtonUp(0)){ if (Physics.Raycast(ray, out hit) && hit.transform.tag == "top"){ Vector3 sutCek = TopaVurus(hit.point, TopAgirligi); fizik.AddForce(-sutCek, ForceMode.Impulse); fizik.velocity = new Vector3(0, (Input.mousePosition.y * TopaVurusHizi) / 10f, 0); } TopaVurusHizi = 0; }
Update() fonksiyonundan devam ediyoruz.Az önce yazmış olduğumuz koşulun hemen altına bu kodları yazıyoruz.Bu kodda da, yine bir koşul oluşturuyoruz.Bu sefer farenin sağ tuşundan elimizi çektiğimiz zaman koşulumuz doğru oluyor.Daha doğrusu aktif oluyor.İkinci satırda, az önceki gibi, etiketi “top” olan nesnenin üzerindeysek koşulumuz gerçekleşiyor.Üçüncü satırda, yeni bir Vector3 oluşturuyoruz ve topumuz için oluşturduğumuz fonksiyona eşitliyoruz.
Bu fonksiyon hatırlarsanız iki parametre alıyordu.İlk parametreye, ışın noktasını ekliyoruz.İkinci parametreye ise, “TopAgirligi” değişkenini ekliyoruz.Bu değişkenimizin değerini ne kadar yüksek tutarsak, topumuz o kadar yavaş gider.Dördüncü satırda, Rigidbody bileşenini eklediğimiz fizik değişkenini kullanarak bir kuvvet oluşturuyoruz.Bunu AddForce fonksiyonu ile yapıyoruz.ForceMode.Impulse fonksiyonu ile, topumuzun üzerindeki kuvveti kullanabiliyoruz.
Beşinci satırda, topumuzu havalandırmak için velocity fonksiyonundan yararlanıyoruz.Topu sadece havalandırırken sadece y eksenini kullanıyoruz.Bunu yaparkende, farenin y eksenindeki pozisyonu ile “TopaVurusHizi” değişkenindeki değeri çarpıyoruz ve çıkan sonucu ona “10” bölüyoruz.Son satırda ise, “TopaVurusHizi ” değişkeninin değerini sıfırlıyoruz.Script dosyamızı bitirdik.
Evet bu dersimizin de sonuna geldik.Özellikle matematik bilgisi gerektiren işlemler yaptığımız için, o bölümleri sizi çok sıkmadan anlatmaya çalıştım.Ben sadece temeli oluşturdum.Siz projenize göre isterseniz daha fazla mekanik ekleyebilirsiniz.Orası sizin hayal gücünüze kalmış.Bir sonraki yazıda görüşmek üzere…
Vector3 sutCek = TopaVurus(hit.point, TopaVurusAcisi);
TopaVurus adı geçerli bağlamda yok hatası alıyorum çözümü nedir?
Merhaba, bu hata genelde değişkenlerin sınıf bağlamında oluşturulmadığı zaman ortaya çıkar.Oluşturduğunuz değişkenleri tekrar kontrol etmenizi öneririm.Hepsinin, Start() metodunun üzerinde yer alması gerekiyor.
Hocam tekrar kontrol ettim sildim baştan yazdım lakin hata aynı değişmedi
Merhaba, admin@ahmetguler.org adresine kontrol edebilmem için projenizi gönderebilir misiniz?
Gönderdim hocam
Merhaba, gerekli açıklamayı ve güncellenmiş dosyayı mail üzerinden paylaştım.
Çok teşekkür ederim hocam
Rica ederim.
Merhaba,
Şöyle bir hata aldım:
NullReferenceException: Object reference not set to an instance of an object
AtisSc.Update () (at Assets/Script/AtisSc.cs:38)
AtisSc: Scriptin adı
38. Satır: Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
Ne yapmak gerekir? Yardımcı olabilirmisiniz?
Merhaba, bu hata ilgili nesneye herhangi bir değer atanmadığı zaman ortaya çıkar.Sadece bu satıra bakacak olursak, kamera nesnenizde bir sorun var gibi gözüküyor.
Tekrar Merhaba,
Camerayı silip yeniden ekledim, Tag kısmına main kamera seçtim. O hata düzeldi fakat başka bir hatam daha var top sadece yukarı zıplıyor. konsol da şöyle bir hata veriyor: (Unity 2021.1.17f1 kullanıyorum bu arada)
rigidbody.force assign attempt for ‘Sphere’ is not valid. Input force is { -Infinity, NaN, Infinity }.
UnityEngine.Rigidbody:AddForce (UnityEngine.Vector3,UnityEngine.ForceMode)
AtisSc:Update () (at Assets/Script/AtisSc.cs:54)
Merhaba, admin@ahmetguler.org adresine projenizi mail yoluyla gönderebilir misiniz?
Merhaba Hocam
Proje indirme linkini mail adresinize gönderdim.
Yardımlarınız için teşekkürler
Merhaba, geri dönüş yaptım.