GÜNCELLEME (29.12.2019): Kod C#’a çevrildi.
Yine ve yeniden merhabalar,
Bu mini derste Unity 3D‘de Mathf.Lerp fonksiyonunu kullanarak istediğimiz bir işlemi “yumuşatmayı” göreceğiz. Yumuşatmadan kastım bir değerden başka bir değere geçişi küt diye değil de adım adım yapmak.
Örneğin kameraya oyuncuyu yumuşak bir şekilde takip etmesini söylerseniz, oyuncu ileri giderken kamera biraz geride kalır, oyuncu geri giderken kamera oyuncuya biraz daha yaklaşır. Böylece “yumuşak” bir animasyon ortaya çıkar. Veya bir objenin sürekli fare imlecine doğru hareket etmesini istiyorsunuz diyelim, bu iş için de Lerp’ten faydalanabilirsiniz. Lerp için daha pek çok örnek üretilebilir; bu daha çok sizin hayal gücünüze kalmış bir şey.
Hazırsanız başlayalım…
İlk önce Lerp fonksiyonunun nasıl çalıştığına bakalım. Bu fonksiyon aslında çok basit bir işleyişe sahip: tek yaptığı şey a ve b sayılarının arasındaki bir değeri döndürmek. Bu değerin a veya b’den ne kadar uzak olacağını ise üçüncü parametre belirliyor. Şöyle ki:
- Mathf.Lerp( 0, 100, 0.5 ): 0 ile 100 sayılarının tam ortasındaki sayıyı (50) döndürür.
- Mathf.Lerp( 0, 100, 0.75 ): Döndürülen sayının 0’a uzaklığı %75 iken 100’e uzaklığı %25 olacak, yani 75 döndürülecek.
- Mathf.Lerp( 100, 500, 0.1 ): Döndürülen sayının 100’e uzaklığı %10 iken 500’e uzaklığı %90 olacak. Aradaki uzaklık 400 olduğuna göre bu uzaklığın %10’u 40’tır. O halde döndürülen sayı 100+40=140 olacak.
NOT: Üçüncü parametre 0.0 ile 1.0 arasında değilse Unity tarafından otomatik olarak ya 0 ya da 1 yapılır.
Peki yumuşak geçiş olayı nasıl gerçekleşiyor? Mesela şu kodu ele alalım:
float a = 0f;
float b = 100f;
void Update()
{
a = Mathf.Lerp( a, b, 0.5f );
}
Update ilk kez çağrıldığında a’nın değeri 0 ile 100’ün ortasındaki sayı, yani 50 olacak. Update ikince kez çağrıldığında a’nın değeri 50 ile 100’ün arasındaki sayı, yani 75 olacak. Sonraki frame’de 87.5 diyerekten böyle böyle a sayısı b sayısına yaklaşacak. Fonksiyondaki 0.5’i artırırsak a daha hızlı yaklaşır, azaltırsak daha yavaş yaklaşır.
Bunu bir örnek vasıtasıyla pekiştirelim: ekranımızda ufak bir UI button olsun ve bu buton ekranda fare imlecini takip etsin. Burada a değerimiz butonun pozisyonu, b değerimiz ise fare imlecinin pozisyonu olduğu taktirde buton fareyi takip eder. O halde sahnenizde GameObject-UI-Button yoluyla bir buton oluşturup butona şu kodu verin:
void Update()
{
Vector3 butonPozisyon = transform.position;
Vector3 imlecPozisyon = Input.mousePosition;
transform.position = Vector3.Lerp( butonPozisyon, imlecPozisyon, 0.25f );
}
Burada Vector3.Lerp kullanıyoruz. Bu fonksiyon iki sayıyı birbirine yaklaştırmak yerine iki vektörü birbirine yaklaştırmaya yarar. Bunu kullanıyoruz çünkü butonun konumu (transform.position) bir Vector3’te depolanmakta.
Kodda yaptığımız şey çok basit: a’ya (butonPozisyon) butonun position’ını, b’ye (imlecPozisyon) ise fare imlecinin position’ını depoluyoruz ve a’yı her frame’de %25 oranla b’ye yaklaştırıyoruz. Vector3.Lerp’in döndürdüğü değeri geri butonun position’ına atmayı unutmuyoruz. Buradaki 0.25’i artırıp azaltarak Lerp’in etkisini rahatça görebilirsiniz.
Peki diyelim ki eğer ekrana tıklarsak tam 2 saniye içinde butonun rengini mevcut renginden yeşile çevirmek istiyoruz. Bu geçişi öyle istiyoruz ki her frame’de rengin değeri eşit olarak değişecek. Burada Color.Lerp fonksiyonu kullanacağız. Bu fonksiyon, a renginden b rengine yumuşak geçiş yapmaya yarar. a kısmına butonun ilk rengini, b kısmına ise yeşil rengi yazacağız. Fonksiyonun istediğimiz gibi çalışması için 3. parametrenin 2 saniye içinde 0’dan 1’e değişmesi lazım. Bunun için kodu şöyle güncelleyin:
using UnityEngine;
using UnityEngine.UI;
public class RenkLerpTest : MonoBehaviour
{
private Color butonIlkRenk;
public Color butonSonRenk = Color.green;
public float gecisSuresi = 2.0f;
private float bitisAni = -1.0f;
private Image imageObjesi;
void Start()
{
imageObjesi = GetComponent<Image>();
butonIlkRenk = imageObjesi.color;
}
void Update()
{
// Butonu imlece yaklaştır
Vector3 butonPozisyon = transform.position;
Vector3 imlecPozisyon = Input.mousePosition;
transform.position = Vector3.Lerp( butonPozisyon, imlecPozisyon, 0.25f );
// Ekrana tıklayınca butonun rengini 2 saniye içinde yeşil yap
if( Input.GetMouseButtonDown( 0 ) )
{
bitisAni = Time.time + gecisSuresi;
}
if( bitisAni > 0 )
{
imageObjesi.color = Color.Lerp( butonIlkRenk, butonSonRenk, 1.0f - ( bitisAni - Time.time ) / gecisSuresi );
// Eğer renk geçişi tamamlanmışsa artık Lerp'ü boş yere çağırma
if( Time.time > bitisAni )
bitisAni = -1.0f;
}
}
}
Kod birazcık uzadı ancak her frame’de eşit aralıklarla b’ye yaklaşmak için biraz daha fazla kod gerekiyordu.
Öncelikle Start fonksiyonunda butonIlkRenk değişkenine butonun ilk baştaki rengini değer olarak veriyoruz. Lerp fonksiyonunda da bu değişkenden faydalanıyoruz. Yani a’ya değer olarak butonun mevcut rengini değil de butonun ilk rengini veriyoruz. Sadece Lerp’ün üçüncü parametresi değişiyor ve böylece her frame’de renk değişimi eşit oluyor. Unity’nin UI sistemiyle çalıştığımız için en başta “using UnityEngine.UI;” kullanıyoruz. Butona “GetComponent<Image>()” ile ulaşırken butonun rengine de “imageObjesi.color” şeklinde erişiyoruz.
Update fonksiyonunda “Input.GetMouseButtonDown(0)” ile ekrana sol tıklanıp tıklanmadığını kontrol ediyor, eğer tıklanmışsa bitisAni değişkeninin değerini mevcut anın (Time.time) 2 saniye sonrası olarak veriyoruz. Buradaki Time.time hazır bir değişken ve oyun başladıktan itibaren kaç saniye geçtiğini depolamakta. Değeri Unity tarafından otomatik olarak güncelleniyor.
Update’in sonunda ise “if( bitisAni > 0 )” koşuluyla ekrana tıklanıp tıklanmadığını kontrol ediyoruz. Eğer tıklanmışsa butonun rengini Color.Lerp’in sonucuna ayarlıyoruz. Asıl kritik satır da tahmin edebileceğiniz üzere burası. a’ya değer olarak butonun ilk rengini, b’ye değer olarak ise yeşil renk (butonSonRenk = Color.green) veriyoruz. Peki %’yi nasıl hesaplıyoruz? Bunu açıklamaya çalışmak yerine matematiksel olarak göstermek daha kolay geliyor (butona tam olarak oyunun 5. saniyesinde (Time.time = 5 iken) bastığımızı varsayalım; bu durumda bitisAni ise 5.0 + 2.0 = 7.0 oluyor):
- Ekrana tıkladığımız frame’de:
1.0 – ( 7.0 – 5.0 ) / 2.0 = 1.0 – 1.0 = 0.0 (butonun rengi butonIlkRenk)
- Ekrana tıkladıktan bir saniye sonra (Time.time = 6 iken):
1.0 – ( 7.0 – 6.0 ) / 2.0 = 1.0 – 0.5 = 0.5 (butonun rengi artık butonIlkRenk ile butonSonRenk’in tam ortasındaki renk)
- Ekrana tıkladıktan iki saniye sonra (Time.time = 7 iken):
1.0 – ( 7.0 – 7.0 ) / 2.0 = 1.0 – 0.0 = 1.0 (butonun rengi artık butonSonRenk, yani yeşil)
Gördüğünüz gibi üçüncü parametremiz 2 saniye içinde 0’dan 1’e çıkıyor. Lerp’ten hemen sonra Time.time’ın bitisAni’na yetişip yetişmediğine bakıyoruz. Eğer yetişmiş ise renk geçişi bitmiş demektir, bu durumda bitisAni’nı 0’dan küçük bir değere ayarlayarak if’in içinin artık çalıştırılmasını önlüyoruz. Eğer bu işlemi yapmasaydık örnek yine birebir aynı çalışırdı zira üçüncü parametre artık 1.0’dan büyük bir değer alır ancak bu değer Unity tarafından otomatik olarak 1.0’a döndürülürdü ancak boş yere neden Lerp çağıralım ki, değil mi?
Bu derse burada noktayı koyuyorum. Umarım konu az biraz anlaşılmıştır. Daha başka derslerde görüşmek üzere!
Hocam çok başarılı sizler biz yeni yetmelere öncülük ediyorsunuz.
Estağfurullah, rica ederim.
Teşekkürler
çok teşekkür ederim güzel ders olmuş tam anlayamadığım bir konuyu çözümledim sayende 🙂
Rica ederim.