Jika ini adalah pertama kalinya Anda pada pertanyaan ini, saya sarankan membaca bagian pra-pembaruan di bawah ini terlebih dahulu, lalu bagian ini. Berikut adalah sintesis masalah:
Pada dasarnya, saya memiliki mesin pendeteksi tabrakan dan resolusi dengan sistem partisi spasial grid di mana urutan-tabrakan dan kelompok tabrakan penting. Satu tubuh pada suatu waktu harus bergerak, kemudian mendeteksi tabrakan, lalu menyelesaikan tabrakan. Jika saya memindahkan semua benda sekaligus, maka menghasilkan kemungkinan pasangan tabrakan, itu jelas lebih cepat, tetapi resolusi pecah karena urutan tabrakan tidak dihormati. Jika saya menggerakkan satu tubuh sekali waktu, saya dipaksa untuk mendapatkan tubuh untuk memeriksa tabrakan, dan itu menjadi masalah. Letakkan kelompok dalam campuran, dan Anda dapat membayangkan mengapa itu menjadi sangat lambat sangat cepat dengan banyak tubuh.
Pembaruan: Saya telah bekerja sangat keras dalam hal ini, tetapi tidak dapat mengelola untuk mengoptimalkan apa pun.
Saya juga menemukan masalah besar : mesin saya tergantung pesanan.
Saya mencoba implementasi generasi tabrakan yang unik , yang pasti mempercepat semuanya, tetapi mematahkan urutan tabrakan .
Biarkan saya jelaskan:
dalam desain asli saya (tidak menghasilkan pasangan), ini terjadi:
- satu tubuh bergerak
- setelah bergerak, ia menyegarkan sel-selnya dan membuat tubuh yang bertabrakan dengannya
- jika tumpang tindih dengan benda yang harus diatasi, selesaikan tabrakan
ini berarti bahwa jika suatu benda bergerak, dan mengenai dinding (atau benda lain mana pun), hanya benda yang telah bergerak yang akan menyelesaikan tabrakannya dan benda lainnya tidak akan terpengaruh.
Ini adalah perilaku yang saya inginkan .
Saya mengerti itu tidak umum untuk mesin fisika, tetapi memiliki banyak keuntungan untuk game bergaya retro .
dalam desain kisi biasa (menghasilkan pasangan unik), ini terjadi:
- semua tubuh bergerak
- setelah semua tubuh bergerak, segarkan semua sel
- menghasilkan pasangan tabrakan yang unik
- untuk setiap pasangan, menangani deteksi dan resolusi tabrakan
dalam hal ini gerakan simultan bisa mengakibatkan dua tubuh tumpang tindih, dan mereka akan menyelesaikan pada saat yang sama - ini secara efektif membuat tubuh "saling mendorong", dan merusak stabilitas tabrakan dengan banyak benda
Perilaku ini umum untuk mesin fisika, tetapi tidak dapat diterima dalam kasus saya .
Saya juga menemukan masalah lain, yang utama (bahkan jika itu tidak mungkin terjadi dalam situasi dunia nyata):
- pertimbangkan badan kelompok A, B dan W
- A bertabrakan dan memutuskan melawan W dan A
- B bertabrakan dan memutuskan melawan W dan B
- A tidak melakukan apa pun terhadap B
- B tidak melakukan apa pun terhadap A
mungkin ada situasi di mana banyak tubuh A dan tubuh B menempati sel yang sama - dalam hal ini, ada banyak iterasi yang tidak perlu antara tubuh yang tidak boleh bereaksi satu sama lain (atau hanya mendeteksi tabrakan tetapi tidak menyelesaikannya) .
Untuk 100 mayat yang menempati sel yang sama, ini 100 ^ 100 iterasi! Ini terjadi karena pasangan unik tidak dihasilkan - tetapi saya tidak dapat menghasilkan pasangan unik , jika tidak saya akan mendapatkan perilaku yang tidak saya inginkan.
Apakah ada cara untuk mengoptimalkan jenis mesin tabrakan ini?
Ini adalah pedoman yang harus dihormati:
Urutan tabrakan sangat penting!
- Tubuh harus bergerak satu per satu , kemudian memeriksa tabrakan satu per satu , dan menyelesaikan setelah gerakan satu per satu .
Badan harus memiliki 3 bit grup
- Grup : grup yang dimiliki tubuh
- GroupsToCheck : grup yang harus dideteksi tubuh terhadap tabrakan
- GroupsNoResolve : mengelompokkan tubuh yang tidak boleh menyelesaikan tabrakan
- Mungkin ada situasi di mana saya hanya ingin tabrakan terdeteksi tetapi tidak diselesaikan
Pra-perbarui:
Kata Pengantar : Saya sadar bahwa mengoptimalkan hambatan ini bukanlah suatu keharusan - mesin sudah sangat cepat. Saya, bagaimanapun, untuk tujuan yang menyenangkan dan mendidik, akan senang menemukan cara untuk membuat mesin lebih cepat.
Saya membuat mesin pendeteksi / respons tabrakan C ++ 2D untuk keperluan umum, dengan penekanan pada fleksibilitas dan kecepatan.
Berikut diagram arsitekturnya yang sangat mendasar:
Pada dasarnya, kelas utamanya adalah World
, yang memiliki (mengelola memori) dari a ResolverBase*
, a SpatialBase*
dan a vector<Body*>
.
SpatialBase
adalah kelas virtual murni yang berurusan dengan deteksi tabrakan fase luas.
ResolverBase
adalah kelas virtual murni yang berurusan dengan resolusi tabrakan.
Tubuh berkomunikasi World::SpatialBase*
dengan SpatialInfo
benda - benda, yang dimiliki oleh tubuh itu sendiri.
Saat ini ada satu kelas spasial:, yang merupakan Grid : SpatialBase
grid 2D tetap dasar. Ini memiliki kelas info sendiri GridInfo : SpatialInfo
,.
Begini tampilannya arsitekturnya:
The Grid
kelas memiliki array 2D Cell*
. The Cell
kelas berisi kumpulan (tidak dimiliki) Body*
: a vector<Body*>
yang berisi semua mayat yang ada di sel.
GridInfo
benda juga mengandung petunjuk yang tidak memiliki sel-sel di mana tubuh berada.
Seperti yang saya katakan sebelumnya, mesin didasarkan pada kelompok.
Body::getGroups()
mengembalikan astd::bitset
dari semua grup yang menjadi bagian tubuh.Body::getGroupsToCheck()
mengembalikan astd::bitset
dari semua grup yang harus diperiksa oleh tubuh terhadap benturan
Tubuh dapat menempati lebih dari satu sel. GridInfo selalu menyimpan pointer yang tidak memiliki ke sel yang ditempati.
Setelah satu tubuh bergerak, deteksi tabrakan terjadi. Saya berasumsi bahwa semua benda adalah kotak pembatas sumbu-sejajar.
Cara kerja deteksi tabrakan fase lebar:
Bagian 1: pembaruan info spasial
Untuk masing-masing Body
body
:
- Sel yang ditempati paling kiri atas dan sel yang ditempati paling kanan bawah dihitung.
- Jika mereka berbeda dari sel-sel sebelumnya,
body.gridInfo.cells
dibersihkan, dan diisi dengan semua sel yang ditempati tubuh (2D untuk loop dari sel paling kiri atas ke sel paling kanan bawah).
body
sekarang dijamin untuk mengetahui sel apa yang ditempatinya.
Bagian 2: cek tabrakan yang sebenarnya
Untuk masing-masing Body
body
:
body.gridInfo.handleCollisions
disebut:
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);
}
Tabrakan kemudian diselesaikan untuk setiap tubuh di
bodiesToResolve
.Itu dia.
Jadi, saya sudah mencoba untuk mengoptimalkan deteksi tabrakan fase luas ini cukup lama sekarang. Setiap kali saya mencoba sesuatu yang lain dari arsitektur / setup saat ini, sesuatu tidak berjalan sesuai rencana atau saya membuat asumsi tentang simulasi yang kemudian terbukti salah.
Pertanyaan saya adalah: bagaimana saya bisa mengoptimalkan fase luas dari mesin tabrakan saya ?
Apakah ada beberapa optimasi C ++ ajaib yang dapat diterapkan di sini?
Dapatkah arsitektur dirancang ulang untuk memungkinkan kinerja yang lebih baik?
- Implementasi aktual: SSVSCollsion
- Body.h , Body.cpp
- World.h , World.cpp
- Grid.h , Grid.cpp
- Cell.h , Cell.cpp
- GridInfo.h , GridInfo.cpp
Output callgrind untuk versi terbaru: http://txtup.co/rLJgz
getBodiesToCheck()
dipanggil 5462334 kali, dan mengambil 35,1% dari seluruh waktu pembuatan profil (Waktu akses baca instruksi)