Bu soruya ilk kez geliyorsanız, önce aşağıdaki ön güncelleme bölümünü, ardından bu bölümü okumanızı öneririz. Yine de sorunun bir sentezi:
Temel olarak, çarpışma sırası ve çarpışma gruplarının önemli olduğu bir ızgara uzamsal bölümleme sistemine sahip bir çarpışma algılama ve çözünürlük motorum var. Her seferinde bir gövde hareket etmeli, sonra çarpışmayı tespit etmeli, ardından çarpışmaları çözmelidir. Tüm bedenleri bir kerede hareket ettirirsem, daha sonra olası çarpışma çiftleri üretirsem, bu daha hızlıdır, ancak çözünürlük kırılır, çünkü çarpışma sırasına uyulmaz. Bir gövdeyi bir seferde hareket ettirirsem, bedenleri çarpışmaları kontrol ettirmeye zorlarım ve bu bir ^ 2 problemi haline gelir. Grupları karışıma koyun ve birçok gövdede neden çok yavaş yavaş olduğunu hayal edebilirsiniz.
Güncelleme: Bu konuda çok çalıştım, ancak hiçbir şeyi optimize etmeyi başaramadım.
Ayrıca büyük bir sorun keşfettim : motorum çarpışma sırasına bağlı.
Her şeyi kesinlikle çok hızlandıran, ancak çarpışma sırasını bozan benzersiz çarpışma çifti nesli uygulamasını denedim .
Açıklamama izin ver:
Orijinal tasarımımda (çift oluşturmama), bu olur:
- tek bir beden hareket eder
- taşındıktan sonra hücrelerini yeniler ve çarpıştığı bedenleri alır
- eğer çözmesi gereken bir bedenle çakışıyorsa, çarpışmayı giderin
bu, bir cismin hareket etmesi ve bir duvara (veya başka bir cisme) çarpması durumunda, sadece hareket eden cismin çarpışmasını çözeceği ve diğer cismin etkilenmeyeceği anlamına gelir.
İstediğim davranış bu .
Fizik motorları için yaygın olmadığını anlıyorum, ancak retro tarzı oyunlar için birçok avantajı var .
olağan ızgara tasarımında (benzersiz çiftler oluşturma), bu olur:
- tüm bedenler hareket eder
- tüm bedenler taşındıktan sonra tüm hücreleri yenile
- benzersiz çarpışma çiftleri üret
- her çift için, çarpışma algılama ve çözünürlük işlemek
bu durumda, eşzamanlı bir hareket iki cismin üst üste binmesine neden olabilir ve aynı zamanda çözülürler - bu, cisimlerin etkili bir şekilde "birbirlerini itmesini" sağlar ve birden fazla cisimle çarpışma kararlılığını bozar
Bu davranış fizik motorları için yaygındır, ancak benim durumumda kabul edilemez .
Ayrıca önemli olan başka bir sorun buldum (gerçek dünya durumunda olma ihtimali olmasa bile):
- A, B ve W grubu organlarını düşünün
- A çarpışır ve W ve A'ya karşı çözer
- B çarpışır ve W ve B'ye karşı çözer
- A, B'ye karşı hiçbir şey yapmaz
- B, A'ya karşı hiçbir şey yapmaz
bir çok A gövdesi ve B gövdesinin aynı hücreyi işgal ettiği bir durum olabilir - bu durumda, bedenler arasında birbirine tepki vermemesi gereken (veya sadece çarpışmayı tespit eden ancak onları çözmeyen) çok fazla gereksiz yineleme vardır. .
Aynı hücreyi işgal eden 100 beden için, 100 ^ 100 yineleme! Bu, benzersiz çiftlerin üretilmemesi nedeniyle olur - ancak benzersiz çiftler oluşturamıyorum , aksi takdirde arzu etmediğim bir davranış elde ederim.
Bu tür çarpışma motorunu optimize etmenin bir yolu var mı?
Bunlar, uyulması gereken yönergelerdir:
Çarpışma sırası son derece önemlidir!
- Oluşumu taşımanız gerekir birer birer , sonra çarpışmaları denetlemek teker teker ve çözmek hareketi sonrasında birer birer .
Gövdelerde 3 grup biti bulunmalıdır
- Gruplar : vücudun ait olduğu gruplar
- GroupsToCheck : vücudun çarpışmayı tespit etmesi gereken grupları
- Çözülmeyen Çözümler : Vücudun çarpışmayı çözmemesi gereken grupları
- Yalnızca bir çarpışmanın algılanmasını istediğim, ancak çözülmediği durumlar olabilir
Ön güncelleme:
Önsöz : Bu darboğazın optimize edilmesinin bir gereklilik olmadığının farkındayım - motor zaten çok hızlı. Bununla birlikte, eğlenceli ve eğitim amaçlı olarak, motoru daha da hızlı hale getirmenin bir yolunu bulmak isterim.
Genel amaçlı bir C ++ 2D çarpışma algılama / yanıt motoru oluşturuyorum, esnekliğe ve hıza önem veriyorum.
İşte mimarisinin çok temel bir şeması:
Temel olarak, ana sınıf, World
a ResolverBase*
, a SpatialBase*
ve a'nın sahibi (hafızayı yönetir) vector<Body*>
.
SpatialBase
geniş fazlı çarpışma tespitiyle uğraşan saf bir sanal sınıftır.
ResolverBase
çarpışma çözünürlüğü ile ilgilenen saf bir sanal sınıftır.
Bedenler , kendilerine ait World::SpatialBase*
olan SpatialInfo
nesnelerle iletişim kurarlar.
Currenly bir mekansal sınıf var: Grid : SpatialBase
temel bir sabit 2B ızgara. Kendi bilgi sınıfı var GridInfo : SpatialInfo
.
Mimarisi şöyle görünüyor:
Grid
Sınıf bir 2D dizi sahiptir Cell*
. Cell
Sınıf bir koleksiyon (sahibi değil) içerir Body*
: Bir vector<Body*>
hücrede tüm organları içeren.
GridInfo
nesneler ayrıca vücudun içinde bulunduğu hücrelere sahip olmayan işaretçiler içerir.
Daha önce söylediğim gibi, motor gruplara dayanıyor.
Body::getGroups()
std::bitset
vücudun parçası olduğu tüm gruplardan birisini döndürür .Body::getGroupsToCheck()
std::bitset
vücudun çarpışmayı kontrol etmesi gereken tüm gruplardan birini döndürür .
Bedenler tek bir hücreden daha fazlasını işgal edebilir. GridInfo, işgal altındaki hücrelere her zaman sahip olmayan işaretçileri saklar.
Tek bir gövde hareket ettikten sonra çarpışma algılama gerçekleşir. Tüm cisimlerin eksene hizalanmış sınırlayıcı kutular olduğunu varsayıyorum.
Geniş fazlı çarpışma tespiti nasıl çalışır:
Bölüm 1: Konumsal Bilgi Güncellemesi
Her biri için Body
body
:
- En soldaki en işgal edilen hücre ve en sağdaki en işgal edilen hücreler hesaplanır.
- Önceki hücrelerden farklıysa
body.gridInfo.cells
, temizlenir ve vücudun kapladığı tüm hücrelerle doldurulursa (en soldaki hücreden en sağdaki hücreye kadar döngü için 2D).
body
artık hangi hücreleri kapladığını bilecek.
Bölüm 2: Gerçek Çarpışma Kontrolleri
Her biri için Body
body
:
body.gridInfo.handleCollisions
denir:
void GridInfo::handleCollisions(float mFrameTime)
{
static int paint{-1};
++paint;
for(const auto& c : cells)
for(const auto& b : c->getBodies())
{
if(b->paint == paint) continue;
base.handleCollision(mFrameTime, b);
b->paint = paint;
}
}
void Body::handleCollision(float mFrameTime, Body* mBody)
{
if(mBody == this || !mustCheck(*mBody) || !shape.isOverlapping(mBody->getShape())) return;
auto intersection(getMinIntersection(shape, mBody->getShape()));
onDetection({*mBody, mFrameTime, mBody->getUserData(), intersection});
mBody->onDetection({*this, mFrameTime, userData, -intersection});
if(!resolve || mustIgnoreResolution(*mBody)) return;
bodiesToResolve.push_back(mBody);
}
Çarpışma daha sonra içindeki her beden için çözülür
bodiesToResolve
.Bu kadar.
Bu geniş fazlı çarpışma tespitini bir süredir optimize etmeye çalışıyorum. Mevcut mimari / kurulumdan başka bir şey denediğimde, bir şey planlandığı gibi gitmez ya da daha sonra yanlış olduğu kanıtlanan simülasyon hakkında varsayımda bulunurum.
Sorum şu: Çarpışma motorumun geniş fazını nasıl optimize edebilirim ?
Burada uygulanabilecek bir çeşit sihirli C ++ optimizasyonu var mı?
Daha fazla performans elde etmek için mimari yeniden tasarlanabilir mi?
- Gerçek uygulama: SSVSCollsion
- Body.h , Body.cpp
- World.h , World.cpp
- Grid.h , Grid.cpp
- Cell.h , Cell.cpp
- GridInfo.h , GridInfo.cpp
En son sürüm için callgrind çıktısı: http://txtup.co/rLJgz
getBodiesToCheck()
5462334 kez çağrıldı ve tüm profil oluşturma süresinin% 35,1'ini aldı (Talimat okuma erişim süresi)