p5.js Editörü ile Taş Makas Kağıt

 

Bildiğimiz klasik taş makas kağıt oyunundan biraz farklı bir versiyon. Ekranda rastgele yönlerde ve rastgele hızlarda hareket etmekte olan belli sayıda taş, makas ve kağıt var. Bunlar ekran kenarlarından sekerek havada (öhöm pardon ekranda) süzülüyor. Süzülürken kim kime çarparsa güçlü olan zayıf olanı kendi cinsine çeviriyor. Mesela, bir kağıt bir taş ile çarpışırsa taş kağıda dönüşüyor ve gezinmeye devam ediyorlar. Bir nevi, kapalı alanda popülasyon üstünlüğü savaşı. Bu cengin sonunda mutlaka bir taraf üstünlüğü ele geçiriyor. Geçirmek zorunda da zaten. İzlemesi eğlenceli bir gladyatörler savaşı.

Taş Makas Kağıt Oyunu Nasıl Yapılır?

Önce bir Nesne class yapısı kuralım. nesne.js isminde bir dosya oluşturabiliriz.

class Nesne{
  constructor(tip, x, y){
    this.tip = tip;
    this.konum = createVector(x,y);
    this.yon = createVector(random(-5,5),random(-5,5));
    this.r = 30;
  }
}

Burada ne tanımladık? Tip belirledik. Bu tip 0: taş, 1: kağıt, 2: makas şeklinde nesnenin o anki tipini tutacak. Konum ve yön değerleri vektörel bir değer. Konum değeri nesne oluşturulurken gönderilecek olan x ve y değerleri ile tanımlanacakken, yön değeri o an -5 ila 5 arasında rastgele bir değer ile oluşacak x ve y değerlerine sahip olacak. Nesnenin r yarıçapı algı seviyesi. Nesneler birbiri ile çarpışırken lazım. Ne kadar mesafeye gelince çarpıştıklarını anlayacağız? Nesne kenarlarını dikdörtgen olarak değil de daire olarak düşünmek collapse (çarpışma) tanımlamak için kolaylık olacaktır.

İki cismin çarpıştığı nasıl anlaşılır?

çarpışma örneği

Cisimlerin merkezleri arasında mesafe ikisinin yarıçap toplamına eşit veya küçükse bu iki cisim çarpışmış demektir.

Bunun için öncelikle iki nokta arasındaki mesafeyi analitik geometri kullanarak hesaplayalım. Bunun için p5.js nin dist() fonksiyonu imdadımıza yetişiyor. Geçi "imdat" dememiştik ama yetişmesi önemli şu an.

let mesafe = dist(x1, y1, x2, y2);

Görüldüğü gibi,  bu hazır fonksiyon ile kolaylıkla iki nokta arasındaki mesafeyi hesaplayabiliriz.

Ekranın kenarlarına çarptıkça nesnelerin sekmesi nasıl yapılır?

Eğer x konumu 0'dan küçükse yön vektörünün x değeri -1 ile çarpılır. Eğer x konumu ekran genişliği (width) değerinden büyükse yön vektörünün x değeri -1 ile çarpılır. Kısaca, sınırlar geçilirse yön ters çevrilir. Bunun aynısı, y yönünde de yapılır. İşte örnek kod:

hareket(){
    this.konum.add(this.yon);
    if (this.konum.x > width || this.konum.x < 0){this.yon.x *= -1;}
    if (this.konum.y > height || this.konum.y < 0){this.yon.y *= -1;}
  }

Burada ayrıca konum vektörü ile hız vektörünün toplanmasını da görüyorsunuz. Cismin bulunduğu konum konum vektörüdür. Mesela cisim (50, 150) noktasında duruyor olsun. Bu konumudur. Bu noktada (4, -12) bir hıza sahipse bu da hız vektörüdür. Bir sonraki adımda konumun ne kadar değişeceğini bu hız vektörü belirler. Eğer cismin sabit durmasını istiyorsanız hız vektörünü (0, 0) yapabilirsiniz. Konumun üzerine hız eklense bile konum değişmeyecektir.

Tüm nesnelerin çarpışma kontrolü nasıl yapılır?

Yukarıda mesafenin nasıl ölçüleceğini göstermiştim. Şimdi bir çarpışma fonksiyonu oluşturalım ve her bir nesnenin diğerleri ile nasıl kontrol edileceğine bakalım. Bunun için for döngüsü işimizi görecek.

for (let eleman of nesneler) {

Uygulamanın başında nesneler adlı bir dizi oluşturduk. Herşeyi de sırayla yazmıyorum. Kodlara bakabilirsiniz zaten. Sonra buraya istediğimiz kadar nesneyi attık.

Bu dizideki her bir elemanı çağırıp adına eleman diyoruz. Mevcut elemanımızı bu döngüden gelen tüm elemanlar ile karşılaştırıyoruz.

carpisma(nesneler){
    for (let eleman of nesneler) {
      
      let mesafe = dist(
        this.konum.x,
        this.konum.y,
        eleman.konum.x,
        eleman.konum.y
      );
      
      if(eleman != this && mesafe < 30){
        // 0:taş 1:makas 2:kağıt
        if(eleman.tip == tas && this.tip == makas){this.tip = tas;}
        if(eleman.tip == tas && this.tip == kagit){eleman.tip = kagit;}
        if(eleman.tip == makas && this.tip == kagit){this.tip = makas;}
        if(eleman.tip == makas && this.tip == tas){eleman.tip = tas;}
        if(eleman.tip == kagit && this.tip == tas){this.tip = kagit;}
        if(eleman.tip == kagit && this.tip == makas){eleman.tip = makas;}
      }
    }
  }

Şimdi bunlar nereye yazılacak? Kim kimdir? makas değişkeni nereden çıktı? gibi türlü türlü sorularınız var. Tek tek açıklamam zor olur. Uygulamanın başında sketch.js içine global olarak tas = 0; makas = 1; kagit = 2; şeklinde bir tanımlama yaptım.

Döngü içerisinde her bir elemanı this elemanı ile karşılaştırdım. Tiplerini karşılaştırdım tabiki. Tiplerde kim üstünlük kuruyorsa rakibi kendisine çevirmiş oluyor.

Ana mantık bu şekilde. Gerisi zaten p5.js içerisinde mevcut. Zaten fazla da bir açıklama kalmadı. Bundan sonrası skor ekleme ile görsel bazı ayarlar. CSS ve HTML dosyasına bakmayı da unutmayın. Kodları inceleyebilirsiniz. Bence daha açıklayıcı olacaktır.

Daha yeni Daha eski