Collision Resolution (Çarpışma Çözümü)

Önceki bölümün sonunda çalışan bir çarpışma tespit sistemimiz vardı; ancak top tespit edilen çarpışmalara hiç tepki vermiyordu; tüm tuğlaların içinden düz geçiyordu. Topu çarpıştığı tuğlalardan sektirilmek istiyoruz. Bu bölüm, AABB - daire çarpışma tespit mantığında çarpışma çözümünü nasıl gerçekleştireceğimizi ele alıyor.

Çarpışma olduğunda iki şey yapmak istiyoruz: topu artık diğer nesnenin içinde olmayacak şekilde yeniden konumlandırmak ve topun hız yönünü, nesneden sekiyormuş gibi görünecek şekilde değiştirmek.


Çarpışma Yeniden Konumlandırma

Top nesnesini çarpıştığı AABB dışına yerleştirmek için topun sınırlayıcı kutuya ne kadar girdiğini bulmamız gerekiyor:

Çarpışma çözümü - daire AABB

Burada top biraz AABB içine girmiş ve çarpışma tespit edilmiş. Topu şekil dışına çıkarmak istiyoruz; sanki çarpışma olmamış gibi sadece AABB'ye temas etmelidir. AABB içine ne kadar girmemiz gerektiğini bulmak için $\color{brown}{\bar{R}}$ vektörünü almamız gerekiyor; bu vektör, AABB'ye girme miktarıdır. Bu vektörü elde etmek için $\color{green}{\bar{V}}$'yi topun yarıçapından çıkarırız. $\color{green}{\bar{V}}$ ise en yakın nokta $\color{red}{\bar{P}}$ ile topun merkezi $\color{blue}{\bar{C}}$ arasındaki farktır.

$\color{brown}{\bar{R}}$'yi bilerek, top konumunu $\color{brown}{\bar{R}}$ kadar kaydırıp doğrudan AABB'ye karşı konumlandırırız.


Çarpışma Yönü

Ardından çarpışmadan sonra topun hızının nasıl güncelleneceğini belirlememiz gerekiyor. Breakout için şu kuralları kullanıyoruz:

  1. Top bir AABB'nin sağ veya sol tarafıyla çarpışırsa yatay hızı (x) tersine çevrilir.

  2. Top bir AABB'nin alt veya üst tarafıyla çarpışırsa dikey hızı (y) tersine çevrilir.

Peki topun AABB'ye hangi yönden çarptığını nasıl anlarız? Nokta çarpımını (dot product) kullanan daha basit bir yaklaşım var. Kuzeyi, güneyi, doğuyu ve batıyı gösteren dört vektör tanımlayıp bunlarla verilen vektörün nokta çarpımını hesapladığımızda, bu dört yön vektörüyle en yüksek dot product değerini veren yön, vektörün yönüdür:

Direction, oyun sınıfının başlık dosyasında tanımlanan enum'un parçası:


AABB - Daire Çarpışma Çözümü

Çarpışma çözümü için gereken değerleri hesaplamak amacıyla çarpışma fonksiyonundan yalnızca true veya false yerine daha fazla bilgiye ihtiyacımız var. Çarpışmanın gerçekleşip gerçekleşmediğini, hangi yönde gerçekleştiğini ve fark vektörü $\color{brown}{\bar{R}}$'yi içeren bir tuple döndüreceğiz:

CheckCollision fonksiyonunu yalnızca true veya false yerine yönü ve fark vektörünü de döndürecek şekilde güncelliyoruz:

Oyunun DoCollision fonksiyonu artık yalnızca çarpışma olup olmadığını kontrol etmekle kalmıyor, çarpışma gerçekleştiğinde uygun şekilde de davranıyor:

Fonksiyon karmaşık görünse de bu aslında şimdiye kadar tanıtılan kavramların doğrudan koda çevirisidir.


Oyuncu - Top Çarpışmaları

Top ile oyuncu arasındaki çarpışmalar biraz farklı ele alınır; bu durumda topun yatay hızı, paddle'ın merkezinden ne kadar uzakta çarptığına göre güncellenmelidir. Merkeze ne kadar uzaksa yatay hız değişimi o kadar güçlü olmalıdır:

Topun x hızını güncellerken y hızını sabit tutuyoruz; bu, vektörün uzunluğunun sürekli değişeceği anlamına gelir. Bu sorunu gidermek için yeni hız vektörünü normalleştirip eski hız vektörünün uzunluğuyla çarpıyoruz; böylece topun hızı her zaman tutarlı kalıyor.


Yapışkan Paddle Sorunu

Kodu çalıştırdığınızda fark edebileceğiniz büyük bir sorun var: yapışkan paddle (sticky paddle) sorunu. Bu, oyuncu paddle'ın yüksek hızla topa doğru hareket etmesiyle topun merkezinin paddle içine girmesi durumunda ortaya çıkar. Oyun sürekli tüm çarpışmalara tepki vermeye çalışır; top sonunda kurtulduğunda y hızını çok fazla tersine çevirdiğinden yukarı mı yoksa aşağı mı gideceğini bilemez.

Bu davranışı basit bir numarayla düzeltebiliriz; paddle üstünde her zaman çarpışma olduğunu varsayarak y hızını tersine çevirmek yerine her zaman pozitif bir y yönü döndürürüz:


Alt Kenar

Klasik Breakout tarifinde eksik olan son şey, seviyeyi ve oyuncuyu sıfırlayan bir kayıp koşulu. Oyun sınıfının Update fonksiyonunda topun alt kenara ulaşıp ulaşmadığını kontrol ediyoruz; eğer ulaştıysa oyunu sıfırlıyoruz:

ResetLevel ve ResetPlayer fonksiyonları seviyeyi yeniden yükler ve nesnelerin değerlerini başlangıç değerlerine sıfırlar.

Oyun sınıfı kaynak kodu: başlıkarrow-up-right, kodarrow-up-right.


Birkaç Not

Çarpışma tespiti oyun geliştirmenin zor bir konusu. Breakout için kullandığımız çarpışma şeması çok basit ve bu oyun türü için özelleştirilmiştir.

Bu tür çarpışma tespiti ve çözümünün mükemmel olmadığını vurgulamak gerekir. Olası çarpışmaları yalnızca kare başına hesaplar ve yalnızca o zaman adımındaki tam konumlar için; bu, bir nesnenin tek bir kare içinde diğer nesneyi geçecek kadar hızlı hareket edebileceği anlamına gelir. Kare düşmesi yaşandığında bu tür şemalar çalışmayacaktır.

Hâlâ oluşabilecek bazı sorunlar:

  • Top çok hızlı giderse tek bir kare içinde nesneyi tamamen atlayabilir.

  • Top tek bir kare içinde birden fazla nesneyle çarpışırsa hızı iki kez tersine döner; orijinal hızı etkilenmez.

  • Tuğlanın köşesine çarpma, VectorDirection'ın dikey veya yatay yön döndürüp döndürmemesi arasındaki farkı belirleyen tek bir karedeki mesafe nedeniyle yanlış yönde sektirmeye yol açabilir.

Bunlar temel grafik ve oyun geliştirme konularını öğretmeye yönelik bölümler olduğundan kullandığımız çarpışma şeması amacına hizmet ediyor; anlaşılır ve normal senaryolarda gayet iyi çalışıyor. Ancak neredeyse tüm senaryolarda (hareketli nesneler dahil) iyi çalışan daha iyi çarpışma şemalarının var olduğunu — ayrışık eksen teoremi (separating axis theorem) gibi — akılda tutmak gerekir.

2D fizik için Box2Darrow-up-right, uygulamalarınızda fizik ve çarpışma tespitini uygulamak için mükemmel bir kütüphanedir.

Last updated