Oyunlarda Trigonometri

Oyunlarda Trigonometri

Son zamanlarda HTML5 ile birlikte gelen canvas etiketi ve çizim API’ı ile oyun geliştirmek iyice popüler oldu. Artık browser üzerinde oyun ve animasyonlar yapabilmek için flash’a ihtiyaç duyulmaması web için önemli bir ilerlemeydi. Hergün artan kütüphaneler, kaynaklar, kitaplar sayesinde bu canvas elementi çok eğlenceli bir oyuncak haline geldi.

Canvas üzerinde rahatça bir şeyler yapabilmek için azbuçuk trigonometri gerekiyor. Aslında bu sadece canvas için geçerli değil. Trigonomi fonksiyonları çizim yaptığını herhangi bir platformda işinize çok çok yaramakta.

Bir şeyler yapmaya başlamadan önce canvas hakkında birkaç bilgi vereceğim. Aslında bir canvas nasıl oluşturulur, javascript ile buna nasıl çizim yapılır gibi şeylerden bahsetmek istemiyorum, çünkü zaten çok basit ve internette yeterince bununla ilgili kaynak var. Bahsetmek istediğim canvas üzerinde bir şeyler çizerken dikkat etmemiz gereken bir kaç davranışı.

Koordinatlar

Tahmin edeceğiniz üzere iki boyutlu görüntüler canvas üzerinde yatay olan x ve dikey olan y ölçüleriyle ifade ediliyor. Ölçüm canvas’ın sol üst’ünden x ve y değeri 0 olarak başlar.

Açılar

Canvas üzerinde açılar derece yerine radyan birimi ile ifade edilir. Bütün trigonomi fonksiyonları radyan olarak parametre alır ve radyan döner. Peki nedir radyan?

Radyan açıları ifade etmek için kullanılan birimdir. 1 radyan 57,2958 dereceye eşittir. Bu değer bir dairenin, yani 360 derecenin iki pi sayısına bölümüdür.

Radyan ve dereceler arasındaki aşağıdaki gibi dönüştürme yapabiliriz.

var degreeToRadian = function (angle) {
    return angle * Math.PI / 180;
};

var radianToDegree = function (radian) {
    return radian * 180 / Math.PI;
};

Canvas hakkında bilmemiz gereken bir şey de açıların yönüdür. Çoğu çizim ve animasyon sisteminde dereceler saat yönünün tersinde (counterclockwise) ölçülür. Canvas üzerinde ise ölçüleri tam tersi, yani saat yönünde belirtmemiz gerekiyor.

Temel Trigonometri

Aslında animasyonlarda ve oyunlarda kullandığımız çoğu trigonomi fonksiyonu lisede gördüğümüz temel trigonometri seviyesinde.

Bunların javascript’teki karşılıkları aşağıdaki gibi.

Math.sin(0.15) // sinüs
Math.cos(0.30) // kosinüs
Math.tan(0.40) // tanjant

Bu fonksiyonlar parametre olarak radyan almaktadır. Örnek figürdeki x derecesinin açısını verdiğinizde bu değerleri hesaplamaktadır.

Bunlar dışında aklımıza kazımamız gereken 4 fonksiyon daha bulunmaktadır. Bunlar yukarıda saydıklarımızın tersi olan fonksiyonlar.

Math.asin(0.20) // arksinüs
Math.acos(0.20) // arkkosinüs
Math.atan(0.20) // arktanjant
Math.atan2(0.20) // arktanjant

Örneğin asin fonksiyonu sin fonksiyonundan farklı olarak karşının hipotenüse bölümünü alır ve size açıyı döndürür.

Dikkat ettiyseniz iki tane atan fonksiyonu var. Bunu şu şekilde açıklayabilirim.

Math.atan(-20/-2);
Math.atan(20/2);

Bu iki deyimin sonucu aynıdır. Çünkü -20/-2’nin sonucu da 20/2 sonucunun da değeri 10’dur. Beklediğimiz sonuç açının tam tersi olarak verilmesiydi. Ancak durum bu şekilde olduğu için atan fonksiyonu ile bunu bulmamız imkansız. Bundan dolayı çoğu programlama dilinda atan2 adında fonksiyon bulunmaktadır. Bu fonksiyon istenilen iki değerin bölümü yerine iki değeri de ayrı ayrı almaktadır.

Math.atan2(-20, 2)
Math.atan2(20, 2)

Gördüğünüz üzere 3 adet temel trigonomi fonksiyonu, 3+1 adet ters trigonomi fonksiyonumuz var. Şimdi bunlar ile neler yapabileceğimizden bahsetmek istiyorum.

Arktanjant ile başlayalım. Buna en iyi örnek olarak mouse pozisyonuna göre dönen objeleri gösterebilirim. Bununla birçok oyunda karşılaşmışsınızdır.

Yukarıdaki görüntüde ok ile belirttiğim yeri x açısı olacak şekilde cursor’a uzanan bir üçgen hayal edin. Cursor’un kordinantlarını işaretlediğim yerin koordinantlarından çıkardığımızda komşu ve karşı kenarın uzunlularını bulabiliyoruz.

Tanjant bize açının karşı kenarının komşu kenara oranını verir. Bizim elimizde açı değil, uzunluklar var. Dolayısıyla tanjantın ters trigonometri fonksiyonu olan arktanjantı kullanacağız.

canvas.addEventListener('mousemove', function (event) {
    var mouseX = event.offsetX,
        mouseY = event.offsetY,
        objectX = 300,
        objectY = 400;

    var arctangent = Math.atan2(mouseY - objectX,
                                mouseX - objectY);

    context.clearRect(0, 0, canvas.width, canvas.height);

    context.save();
    context.translate(objectX, objectY);
    context.rotate(arctangent);
    context.fillRect(0, 0, 60, 2);
    context.restore();

}.bind(this));

Dikkat ettiyseniz objeyi değil, canvas’ı döndürüyoruz. Bu da animasyonlarda dikkat etmemiz gereken bir nokta. Canvas’ın bulunduğu rotasyonu ve pozisyonları save metodu ile kaydedip, canvas’ı evirip çeviriyoruz. İşimiz bittiğinde ise restore metodu ile eski haline döndürüyoruz.

Sinüs Dalgası

0’dan 360’da kadar olan açıların sinüs değerinin yan yana y ekseninde yansıtılmasıyla sinüs dalgası elde ediyoruz. Canvas üzerinde bunu aşağıdaki gibi çizdirebiliriz.

for (var angle = 0; angle < 360; angle++) {
    var sinValue = Math.sin(degreeToRadian(angle));
    context.fillRect(
        200 + angle,
        200 + radianToDegree(sinValue),
        1,
        1);
}

Örnek üzerinde angle 360’a kadar artan değer x ekseninde, değerin sinüs’ü ise y ekseninde çizdirilmektedir. Bu çizim sinüs dalgasını ifade etmektedir.

Peki neler yapabiliriz biz sinüs dalgasıyla? Açı arttıkça sinüs değeri yükselmekte, bir noktadan sonra düşmekte, en son tekrar 0’a çıkmaktadır.

Örnek olarak bu yöntemle kendi yörüngesinde ya da belirli bir eksende dönen cisimler, yumuşak geçişli animasyonlar yapılabilir.

Yukarıda gördüğünüz animasyon sürekli artan açı değerinin sinüsünün x ekseninde çizdirilmiş halinden ibaret.

var angle = 0;
setInterval(function () {
    // gerçek animasyonlarınızda setInterval yerine
    // requestAnimationFrame kullanmanız daha makbul.
    context.clearRect(0, 0, canvas.width, canvas.height);
    var sinValue = Math.sin(degreeToRadian(++angle)) * 140;
    context.fillRect(
        canvas.width / 2 + sinValue,
        canvas.height / 2,
        40,
        40);
}.bind(this), 1000/60);

Objenin hareket ettiği sahayı genişletmek için sinüs değerini bir sayı ile çarptık. Bu sayı rasgele belirlenmiş bir sayıdır.

Bahsetmek istediklerim bu kadar. Javascript ile oyun geliştirmek çok zevkli. Bu konu hakkında birkaç blog yazısı daha yayınlamayı planlıyorum. Vaktinizi ayırdığınız için teşekkürler 🙂

Alıntıdır

http://blog.fatiherikli.com/post/oyunlarda-trigonometri/