Daha hızlı 2D Çarpışma tespiti


13

Son zamanlarda hızlı tempolu bir 2d atıcı üzerinde çalışıyorum ve güçlü bir sorunla karşılaştım. Çarpışma algılama. Tabii, çalışıyor, ama çok yavaş. Amacım: Ekranda çok fazla düşman bulundurun ve birbirlerine dokunmamalarını sağlayın. Tüm düşmanlar oyuncu varlıklarını kovalar. Birçoğu aynı hızda er ya da geç, oyuncuları kovalarken aynı alanı kaplarlar. Bu gerçekten eğlenceli faktörü düşürüyor çünkü oyuncu için sadece bir düşman tarafından kovalanıyormuşsunuz gibi görünüyor. Aynı alanı almasını önlemek için çarpışma algılama (çok basit bir 2D algılama, bildiğim tek yöntem) ekledim.

Enemy class update method
    Loop through all enemies (continue; if the loop points at this object)
        If enemy object intersects with this object
            Push enemy object away from this enemy object

Bu iyi çalışıyor. Sadece 200'den az düşman varlığım olduğu sürece. 300-350 düşman varlığına yaklaştığımda kare hızım çok düşmeye başlıyor. Önce kötü render olduğunu düşündüm, bu yüzden çekilişini kaldırdım. Bu hiç yardımcı olmadı, bu yüzden güncelleme yöntemi olduğunu fark ettim. Güncelleme yöntemlerindeki tek ağır parça, her düşman-her-düşman-döngü-kısmıdır. 300 düşmana yaklaştığımda oyun 90000 (300x300) adım yineleme yapıyor. Benim ~

Eminim bu çarpışma tespitine yaklaşmanın başka bir yolu olmalı. Buna rağmen hiçbir fikrim yok. Bulduğum sayfalar, iki nesne arasındaki çarpışmanın gerçekte nasıl yapılacağı veya bir nesne ile bir karo arasındaki çarpışmanın nasıl kontrol edileceği ile ilgilidir. Bu iki şeyi zaten biliyorum.

tl; dr? Varlıkların LOTSları arasındaki çarpışma tespitine nasıl yaklaşırım?

Hızlı düzenleme: Herhangi bir yardıma ihtiyacınız varsa, C # XNA kullanıyorum.


İlk etapta 90K'ya gitmeyi nasıl başardığını merak ediyorum. mayın 20K boğuluyor (tam SAT MTV tespiti yapıyorum). Ama mümkün olan tek şey tüm düşmanları dolaşmak. Bununla birlikte, yapmanız gereken şey zaten kontrol edilip edilmediğini kontrol etmektir, çünkü dediğiniz gibi yaparsanız, herkes herkesle iki kez test edilir.
Delusional Logic


@MarkusvonBroady'nin bağlantı kurduğu sorusunda çok iyi bir cevap var.
Cypher

Yanıtlar:


11

Sorununuzu zaten kafadan vuruyorsunuz, her varlığın diğer tüm varlıkları kontrol etmesini sağlıyoruz. İstediğiniz şey, olası çarpışma adaylarının daha iyi seçildiği bir tür `` Ayrıntı Düzeyi '' sistemidir (hemen hemen çok basit bir sahne grafiği, sadece renderleme dışındaki şeyler için kullanıyorsunuz :)).

Genelde böyle sistemler için üç koleksiyon yaparım. Ve sahip olmayı hedeflediğiniz varlıkların sayısı hakkında konuşurken, izleme verileri (her varlık için bir girişi olan varlık başına 3 liste) hızlı bir şekilde çıkabileceği için bunun için tam bir sahne grafiği ile gitmeniz gerekebilir. kontrol.

Temelde üç listeniz olsa. İlki, her karede etkileşimlerle kontrol edeceğiniz çok küçük bir varlık listesi olmalıdır. Bunu, söz konusu varlığın X aralığında olduğu için siz belirlersiniz. Belirtildiği gibi, bu listenin amacı, bu çerçeveyle başka bir çerçeveyle makul bir şekilde çarpışabilecek her varlığı içermektir.

Bir sonraki liste, çok fazla çaba sarf etmeden varlığın aralığına taşınabilecek bir arabellek aralığındaki listelerdir. Bu tartışmayı X * 1.5'e sadece tartışma uğruna çağırırız. Bu, her çerçeve için yalnızca bir avuç güncelleme yapacağınız, ancak düzgün bir şekilde işlerin görünüşünü sürdürecek kadar hızlı geçtiğinizden emin olacağınız zaman dilimli bir listedir.

Üçüncü liste 'diğer her şey' listesidir ve buna sahip olmaktan kaçınmak için bir değer olabilir (Tüm varlık listesini taramak ve belki ilerlemeden önce diğer listelerden birinde olup olmadığını kontrol etmek? Liste boyutlarına bağlı olarak bu işe yarayabilir veya işleri daha da kötüleştirebilir.) Bu listedeki nesneler, diğer iki listeden birine yerleştirilmek için kesinlikle birkaç kareden fazla sürmesi gerektiği için en azından kontrol edilir.

Bunu sürdürmek için yapmanız gereken şey, çarpışma testlerini yaparken, varlıkların hangi listede bulunduğunu güncellediğinizden emin olun. Aralık dışında hareket edenlerin indirgenmesi ve benzer şekilde yaklaşanların bir daha aktif kontrol listesi.

İşleri yeterince basit tuttuğunuzu varsayarsak, bu sizin ihtiyaçlarınıza uygun olmalıdır. Varolan bir oluşturma sahne grafiğine ekstra bilgi ekleyebiliyorsanız (bir tane varsayalım), bu nedenle, bir grafik grafiğin tüm noktası olduğu için daha iyi olabilecek aralık dahilinde olan varlıkların bir listesini almak için sorgulayabilirsiniz. her neyse (bir konuma göre ilgili verilerin listesine hızlı erişim). Bu sadece potansiyel olarak daha fazla iş gerektirir ve her zaman ne yapmanız gerektiğini vs pratikte ne yapmanız gerektiğini düşünmelisiniz.

Bu yardımcı olur umarım.


1
Bu belirsiz bir cevap. Ve bazı çarpışmaları kaçırmayı kabul edebilir miyiz? Çok daha basit, burada bahsettiğim Dörtlü Ağaç gibi yüzey bölümlemesini yapacak bir veri yapısı kullanın. Hatta bir Quad Tree tepegöz önlemek için biraz ince ayar gerekiyor, bu yüzden hakkında konuşmak 'çözüm' karmaşıklığını hayal edemiyorum. Temel programlama kuralı: sadece doğru veri yapısını kullanın.
GameAlchemist

@VincentPiel Bir sahne grafiği dörtlü bir ağaçtan daha karmaşık değildir.
Cypher

@James: Açıkçası daha karmaşık. QuadTree'nin tam hızını kavramanızın bir sakıncası yoksa, internette bir QuadTree lib'i alabilir ve birkaç saat içinde mükemmel bir şekilde çalışmasını sağlayabilirsiniz. Şunun gibi bir soru yok: İlk listeye ne koyarım, ikincisi, üçüncüsü, bir varlığı başka bir listeye koymaya nasıl karar veririm ... ve hiçbir çarpışma kaçırılmaz. Arabanız varken neden bisiklet kullanıyorsunuz?
GameAlchemist

@VincentPiel Sanırım burada benim yerine Cypher'a yaptığınız yorum için @ demek istediniz. Herhangi bir dörtlü ağaç sadece bir tür sahne grafiğidir ve saniyede X kare hızında çalıştığınızı hatırlamanız gerekir. Kaçırılan çarpışmalar fark ederseniz, işleri daha iyi dengelemek için aralık eşiklerini ayarlamanız gerekir. Benim çözümüm, sadece çarpışma şansı olan her kareyi kontrol ettiğinizden emin olmak için çok basit bir yaklaşım ve daha sonra daha yüksek bir önceliğe hak kazanıp kazanmadıklarını görmek için geri kalanı üzerinde arka plan / sınırlı güncellemeler yapma.
James

6

Sıralı veri yapısına sahip çarpışmalarla başa çıkmanız gerekir, böylece korkunç n ^ 2 yerine n * günlüğü (n) kez olabilir. Ve n * log (n) bildiğiniz gibi neredeyse doğrusaldır. Bir (klasik) örnek dörtlüdür, burada grafik ve kod (Java) ile oldukça basit ve iyi yazılmış bir öğretici var:

http://gamedev.tutsplus.com/tutorials/implementation/quick-tip-use-quadtrees-to-detect-likely-collisions-in-2d-space/

Rq: Herhangi bir dilde QuadTrees için bir uygulama bulmak oldukça kolaydır. Yine de, ağaç için doğru 'tanecikliği' düşünmek zorundasınız ve ağaç boyutu ne kadar büyük olursa, bir düğümün içine sığmayan varlıklara o kadar çok sahibiz.
Rq 2: Alan bölümlendirmeniz yalnızca çarpışma tespiti için yapıldığından, alanı istediğiniz gibi bölmek için mükemmel bir özgürlüğe sahipsiniz. Örneğin, dört egal parçaya bölünmezdim, daha ziyade mevcut seviye varlıkların barikatını yeni bölünmenin merkezi olarak kullanırdım. 1) algoritma hala n * log (n), 2) sahneyi ağaçtan 'yeniden inşa etme' olasılığını kaybediyorsun - ama umursamıyorsun - ve 3) çok daha dengeli bir ağacın, daha az tepenin var .
Rq3: Ağacına sahip olduktan sonra, ekran ve objeler arasındaki bir 'çarpışma' sana görünür objeleri verir !! log (n) gibi bir zamanda, n büyükse neden olmasın? (en kötü durum bu yaklaşım için n cinsinden açık bir zamandır.)


Evet, dörtlü ağaç sadece bir tür sahne grafiğidir. Her zaman burada olan insanların kendilerinin bir şeyler yazmak istediğini, başka birinin kütüphanesini kullanmadıklarını varsayıyorum, bu durumda neden dört ağacında durun, sadece tam bir çarpışma kütüphanesi bulun.
James

0

ikili boşluk bölüm ağacı, dörtlü, oktree (3D için) çarpışmanın uygulanmasını istediğiniz her nesne için her güncelleme çağrısında oluşturabileceğiniz (veya hırslıysanız koruyabileceğiniz) olası ağaçlardır.


3
Bu bir yorum yapmak için daha uygun. Cevabınıza daha fazlasını eklemeyi düşünün.

0

Dörtlü veya sekizli ağaç hakkında konuştuğumda oldukça naifim. Ama bu yöntemin yapması gerektiğini düşünüyorum:

Oynatıcı yapısını / sınıfını değiştirmeniz gerekir. Diğer oyuncu yapısına işaretçi dizisi / vektörü ekleyin.

Her iki oyuncu arasındaki her saniye kontrol mesafesi. O kadar düşükse, 1 saniye içinde ulaşmak mümkündür, o zaman o oyuncunun işaretçisini mevcut oyuncunun çarpışma dizisine ekleyin.

Şimdi sadece birbirleri listesindeki oyuncular arasındaki çarpışmayı kontrol edin.

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.