Eğrilerle çarpışma tespiti


12

Hareketli bir daire ve bir tür statik eğriler (belki Bezier eğrileri) arasında çarpışma tespiti yapmak istediğim bir 2D oyun üzerinde çalışıyorum.

Şu anda oyunumda statik geometri olarak sadece düz çizgiler var ve çemberden çizgilere olan mesafeyi hesaplayarak ve mesafenin daire yarıçapından daha az olması durumunda daireyi çizginin dışına yansıtarak çarpışma tespiti yapıyorum.

Bu tür bir çarpışma tespitini göreceli olarak basit bir şekilde nasıl yapabilirim? Mesela Box2D'nin Bezier eğrileriyle çarpışma algılama özelliğine sahip olduğunu biliyorum. Tam özellikli bir çarpışma tespit mekanizmasına ihtiyacım yok, sadece tarif ettiğim şeyi yapabilen bir şey.


GÜNCELLEME: Harika cevaplar için çok teşekkürler! Açıkladığınız yöntemi tam olarak anlamak için Bezier eğrilerini okumam gerekecek. Sonra sana geri döneceğim.

Yanıtlar:


6

29/09/2012 - 23:20

Burada bir git Repo oluşturdum: https://github.com/ArthurWulfWhite/Bezier-Distance/

Kaynak dosyaları buradan zip olarak indirebilirsiniz. Ayrıca FlashDevelop kullanarak derleyebileceğiniz bir demo içerir. Demoyu kullanmak için, Flash Geliştirme'de projeyi açın ve 'Projeyi Test Et'i tıklayın. Demoyu çalıştırırken, yeni bir Bezier eğrisini ve yeni bir Circle'ı rastgele seçmek için LMB'yi tıklayın.

İyi şanslar!

Zip bağlantısını görmek zor - sadece Ctrl + F kullanın ve zip yazın. Bu kaynak birkaç haftalık yeniden arama ve programlama temsil eder, umarım beğenirsiniz.


Çerçeveyi özyinelemeli olarak bölümlere ayırmayı ve onlarla çarpışmaları kontrol etmeyi planlıyorsanız, 100.100 dizi (ızgara) oluşturmanızı ve her bir segmenti en yakın dört kareye yerleştirmenizi öneririm, böylece yalnızca 4 / 10.000 ile çarpışmaları kontrol etmeniz gerekir her kareyi keser.

Box2d'den hem bir programcı hem de bir oyun yaratıcısı olarak faydalanacağınızı düşünüyorum, çünkü hareketi biraz engebeli ve daha az sıvı gibi gösteren 'basit' bir fizik motoru yapmak için birçok gizli küçük engel var.

Eski cevap: Saf yol.

Dairenin merkezi ile eğri üzerindeki en yakın nokta arasındaki mesafeyi kontrol ederek bir dairenin Bezier eğrisi ile çarpışıp çarpışmadığını görebilirsiniz.

Mesafe denklemi (genel olarak)

açıkladı:

Bezier denklemi:

q(t) = (1-t) * ((1-t) * start.(x,y) + t * control.(x,y)) + t*(t * control.(x,y) + (1 - t) * end.(x,y))

Bu, (bazı cebirlerle) toplanabilir - Okunabilirlik için atlayacağım. (X, y) (hala bir sayı değil, puanlardır)

q(t) = (start -2 * cont + end) t^2 + (-2 * start + 2 * control) + start

Noktadan (x, y) uzaklık:

sqrt ((q(t).x - point.x)^2 + (q(t).y - point.y)^2)

Bezier üzerinde topa en yakın noktayı bulmak için, türevin sıfıra eşit olduğu tüm noktaları (kökler) bulmanız ve bulmanız gerekir. Üçüncü dereceden bir polinomdur, bu yüzden kapalı bir formül kullanabilirsiniz, ancak güvenilir olmayan olabilir, çünkü bilgisayar kayan nokta temsil kesimlerinin hassasiyeti yeterli olmayabilir. Newton'u veya bu türden bir şeyi kullanmak çok daha iyidir.

Kökleri bulmanız için gereken türev:

Varsayım: a = başlangıç ​​b = kontrol c = son d = merkez merkez noktası

Volfram alfa kullanarak türev

Zor kısmı bu noktaları çoğaltır, nokta ürünü kullanmanız gerekir.

İsterseniz, bunun için kod var ve burada bir çarpışma olup olmadığını ve bir çarpışma açısı varsa sadece bir boolean döndüren bir işlev şeklinde paylaşabilirsiniz. Böyle bir çarpışma motorunun naif uygulanmasında bazı problemler ortaya çıkabilir, örneğin hızlı hareket eden bir top iki eğri arasında sıkışabilir.

Şimdilik bundan kaçınmanızı öneririm, sadece x ekseni ve y ekseni için katsayıları toplayın ve ekleyin.

Kökleri bulmak için Newton gibi seçebileceğiniz güvenilir bir yöntem kullanın, çerçevedeki kök noktalardan mesafeyi kontrol edin, 0 <= t <= 1 daire merkezine ve çerçevenin iki ucu için mesafeyi kontrol edin (başlangıç ve bitiş) daire merkezine, hangisi en yakınsa, size bir çarpışma olup olmadığını söyleyecektir.

Yarıçap minimum mesafeden daha küçükse, bir çarpışma olur.

Açı, dairenin merkezi ile bezier üzerindeki en yakın nokta arasındaki açıdır.

Bununla birlikte, çarpışma fiziği ile gerçekten bir oyun yapmak istiyorsanız, sadece bezier üzerinde tekrar etmenizi öneririm

    q(t) = (1-t) * ((1-t) * start.(x,y) + t * control.(x,y)) + t*(t * control.(x,y) + (1 - t) * end.(x,y))

Ortadaki her parçayı, yeterince küçük olana kadar tekrar tekrar bölün , 10 piksel veya daha az diyelim, sonra çerçeveyi kabaca kutulardan inşa edin ve fizik için Box2d'yi kullanın , çünkü tüm bu çarpışma algılama kodunun yazılmasının harika olduğunu kanıtlaması mümkündür oyun fazla geliştirmez zaman lavabo. Box2d kullanımı geçmişte sayısız projede kendini kanıtlamıştır.


Eğriye en kısa noktayı hesaplamak için tanımladığınız yöntem, tam olarak eğriler yerine çizgilerle kullandığım yöntemdir. Ama aynı şeyi eğriler için yapmak, açıkladığınız yöntemle biraz fazla karmaşık geliyor. Anladığım kadarıyla, sizin de düşündüğünüz şey. Ve Box2D ile ilgili olarak. Harika bir iş olduğuna eminim. Ama oyunumdaki fizik dürüstçe çok basit ve bu yüzden tam bir fizik motorunun aşırıya kaçmasına karar verdim.
paldepind

Oyununuzda kaç nesne var? Kaç kişi birbiriyle çarpışabilir? Bazen bir Fizik motoru kullanmak, çarpışma süresini doğru olarak hesaplamak gibi büyük faydalar sağlayabilir. (neden çerçeveler ayrık ve çarpışmalar gerçektir (bir çerçeve oluşturduğunuzda tam olarak gerçekleşmez)
AturSams 27:12

Çoğu zaman yeni bir şey uygularken beklenmedik zorluklar ve 2d fizik api kullanmanın güzelliği, herhangi bir programlama dili kullanmak gibi olması, öğrenmeniz için birkaç saat harcamaktan başka bir çaba gerektirmemesi ve sonuçlar çok tatmin edicidir.
AturSams

Şu anda birkaç ayrıntı daha ekledim, iyi şanslar. :)
AturSams

Basit bir Elasto Mania benzeri oyun yaratıyorum. Sadece üç hareketli daire ve statik geometri. Tüm motor bitti ve harika çalışıyor. Geriye kalan tek şey, bu cevaptaki yardım sayesinde atm'yi çözmek üzere olduğum eğrilere izin vermektir :) Belirttiğiniz kodu yayınlamaktan çekinmeyin. Gerçek hayatta kullanmanın ne kadar uygun olacağını düşünüyorsunuz? Bezier'i küçük çizgilere dönüştürmekten daha mı iyi?
paldepind

7

Bunu yapmak için:

  • Bezier eğrisini birkaç çizgi parçasına ayırın ve saklayın.

  • Tüm bu segmentleri tüm eğri için eksene hizalanmış bir sınırlama kutusuna koyun.

Çarpışma algılama :

1) kürenin ana sınırlayıcı kutunun içinde olup olmadığını kontrol edin. hayır ise, çarpışma olmaz.

2) aksi takdirde, yukarıda hesaplanan her bir segmentin küre ile çarpışıp çarpışmadığını kontrol edin. Bkz Wikipedia'dan Line-küre kesişme makalesine .

DÜZENLEME: yüksek hassasiyete ihtiyacınız varsa ve iyi performans istiyorsanız, tüm eğri için bir ana sınırlama kutusu da oluşturabilir, ardından eğriyi iki segmentte alt bölümlere ayırabilirsiniz (örneğin: [0.0 - 0.5]ve [0.5 - 1.0]). Her biri için bir tomurcuklama kutusu oluşturun, daha sonra bu segmentlerin her birini tekrar iki segmente bölün (böylece [0 - 0.25], [0.25 - 0.5]ve [0.5 - 0.75], vererek [0.75 - 1.0]). Yeterince hassasiyet elde edene kadar bu şekilde devam edin. sonunda binary treeyapraklarda kök ve çizgi parçaları ana eğri sınırlama kutusu olan bir sınırlama kutuları olacak . ağaçta arama yapmak size şunu O(log n)verir O(n)(burada n= eğri için satır segmentlerinin sayısı)


Bu çözüm bana mantıklı geliyor ve kesinlikle anlaşılması en kolay olanı ve ben de bununla yetinebilirim. Ama daha "saf" bir seçenek olup olmadığını merak ediyorum.
paldepind

5

Bir çizgi ile Bezier eğrisi arasındaki kesişim, eğri alt bölümlere ayrılarak matematiksel olarak elde edilir. Bu, eğrinin dışbükey gövde özelliğine güvenmek ve bölmeyi et-impera benzeri bir şekilde farklı kontrol çokgenlerine sahip daha küçük yaylara bölmek anlamına gelir.

Bu makale bir noktaya değinmektedir: http://students.cs.byu.edu/~tom/557/text/cic.pdf .

Güzel yanı, algoritmanın herhangi bir çizgiyle çalıştığı, hedef çizginizin Ox eksenine paralel olduğunu düşünebilmeniz için eğriye katı bir dönüşüm uygulamak zorundasınız.

Benzer şekilde, bir Bezier yayını iki alt ark halinde alt gruplara ayırdığınızda, böyle bir bezier arkının dairesine ve çokgenine karşı kontrol edebilirsiniz. Bir eğri-daire testinin anlamlı olması için daire, bir yayın kontrol poligonuyla kesişmelidir.


Makaleyi henüz okumadım. Ancak bir çizgi ile Bezier eğrisi arasındaki kavşaktan daire ve Bezier arasındaki kavşağa nasıl geçebilirim? Bir çember ve bir çokgene karşı çarpışmayı kontrol etmek benim için biraz karmaşık geliyor.
paldepind
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.