Saya membuat game yang terdiri dari banyak objek pada layar, salah satunya adalah pemain. Saya perlu tahu objek mana yang bertabrakan setiap iterasi.
Saya membuat sesuatu seperti ini:
for (o in objects)
{
o.stuff();
for (other in objects)
if (collision(o, other))
doStuff();
bla.draw();
}
Ini memiliki O (n ^ 2), yang menurut saya buruk. Bagaimana saya melakukan ini dengan lebih efisien, mungkinkah? Saya melakukan ini dalam Javascript, dan n biasanya akan lebih rendah dari 30, apakah ini akan menjadi masalah jika ini tetap sama?
Jawaban:
Dengan hanya 30 objek maks, Anda tidak perlu banyak optimasi sama sekali selain untuk tidak memeriksa dua pasangan yang sama satu sama lain lebih dari sekali per frame. Yang akan dicakup contoh kode di bawah ini. Tetapi jika Anda menarik dalam berbagai optimisasi yang akan digunakan mesin fisika, lanjutkan membaca sisa posting ini.
Yang Anda perlukan adalah implementasi partisi spasial , seperti Octree (untuk game 3D) atau Quadtree (untuk game 2D). Ini mempartisi dunia menjadi sub-bagian, dan kemudian masing-masing sub-bagian dipartisi lebih lanjut dalam manor yang sama, sampai mereka dibagi menjadi ukuran minimum. Ini memungkinkan Anda untuk dengan cepat memeriksa objek mana yang berada di wilayah yang sama dengan yang lain di dunia, yang membatasi jumlah tabrakan yang harus Anda periksa.
Selain partisi spasial saya akan merekomendasikan membuat AABB ( Axis-aligned box ) untuk masing-masing objek fisika Anda. Ini memungkinkan Anda untuk memeriksa AABB dari satu objek terhadap yang lain, yang jauh lebih cepat daripada cek per-poli rinci antara objek.
Ini dapat diambil selangkah lebih jauh untuk objek fisika yang rumit atau besar, di mana Anda dapat membagi mesh fisika itu sendiri, memberikan masing-masing sub-bentuk AABB sendiri yang dapat Anda periksa hanya jika AABB dua objek saling tumpang tindih.
Sebagian besar mesin fisika akan menonaktifkan simulasi fisika aktif pada tubuh fisika begitu mereka beristirahat. Ketika sebuah tubuh fisika dinonaktifkan, ia hanya perlu memeriksa tabrakan terhadap AABB setiap frame, dan jika ada sesuatu yang bertabrakan dengan AABB maka ia akan mengaktifkan kembali dan melakukan pemeriksaan tabrakan yang lebih granular. Ini menjaga waktu simulasi turun.
Juga, banyak mesin fisika menggunakan 'pulau simulasi', yang merupakan tempat sekelompok badan fisika yang berdekatan dikelompokkan bersama. Jika semua yang ada di pulau simulasi diam maka pulau simulasi itu sendiri akan dinonaktifkan. Manfaat dari pulau simulasi adalah bahwa semua benda di dalamnya dapat berhenti memeriksa tabrakan begitu pulau tidak aktif, dan satu-satunya memeriksa setiap frame adalah untuk melihat apakah ada sesuatu yang memasuki AABB pulau. Hanya sekali sesuatu memasuki AABB pulau maka masing-masing badan di dalam pulau perlu memeriksa tabrakan. Pulau simulasi juga mengaktifkan kembali jika benda di dalamnya mulai bergerak sendiri. Jika suatu benda bergerak cukup jauh dari pusat kelompok, ia dikeluarkan dari pulau.
Pada akhirnya Anda dibiarkan dengan sesuatu seperti ini (dalam pseudo-code):
Saya juga akan merekomendasikan tidak memiliki begitu banyak loop dalam loop seperti ini, sampel di atas hanya jadi Anda punya ide, saya akan memecahnya menjadi beberapa fungsi yang memberi Anda fungsi yang sama seperti sesuatu seperti yang ditunjukkan di atas.
Juga, pastikan untuk tidak mengubah wadah AABBNodes saat mengulanginya, karena itu bisa berarti cek tabrakan yang terlewat. Ini mungkin terdengar seperti akal sehat, tetapi Anda akan terkejut betapa mudahnya untuk bereaksi terhadap benturan menyebabkan perubahan yang tidak Anda harapkan. Misalnya jika tabrakan menyebabkan salah satu objek bertabrakan untuk mengubah posisi cukup untuk menghapusnya dari AABB dari node Octree yang Anda periksa maka itu dapat mengubah wadah itu. Untuk mengatasi ini, saya sarankan menyimpan daftar semua peristiwa tabrakan yang terjadi selama pemeriksaan, dan kemudian setelah semua pemeriksaan selesai dijalankan melalui daftar dan mengirimkan semua peristiwa tabrakan.
sumber
Contoh Anda menguji setiap pasangan objek beberapa kali.
Mari kita ambil contoh yang sangat sederhana dengan array yang berisi 0,1,2,3
Dengan kode Anda, Anda mendapatkan ini:
Sekarang mari kita lihat kode berikut:
Jika kami menggunakan array yang mengandung 0,1,2,3 sekali lagi, kami memiliki perilaku berikut:
Dengan algoritma kedua kami telah mendapat 6 tes tabrakan, sedangkan yang sebelumnya meminta 12 tes tabrakan.
sumber
N(N-1)/2
perbandingan yang masih O (N ^ 2) kinerja.Rancang algoritme sesuai kebutuhan Anda, tetapi pertahankan detail implemetasinya. Bahkan dalam Javascript, konsep OOP dasar berlaku.
Karena
N =~ 30, O(N*N)
bukan masalah, dan pencarian linier Anda kemungkinan akan sama cepatnya dengan segala alternatif di luar sana. Tetapi Anda tidak ingin asumsi hard-code menjadi kode Anda. Dalam pseudocode, Anda akan memiliki antarmukaItu menjelaskan apa yang dapat dilakukan daftar item Anda. Kemudian Anda bisa menulis kelas ArrayContainer yang mengimplementasikan antarmuka ini. Dalam Javascript, kode akan terlihat seperti ini:
Dan di sini adalah contoh kode yang membuat 300 kotak pembatas dan mendapatkan semua persimpangan. Jika Anda telah mengimplementasikan ArrayContainer dan QuadTreeContainer dengan benar, satu-satunya hal yang perlu Anda ubah dalam kode Anda adalah berubah
var allMyObjects = new ArrayContainer()
menjadivar allMyObjects = QuadTreeContainer()
.Saya melanjutkan dan membuat implementasi untuk standar ArrayContainer di sini:
http://jsfiddle.net/SKkN5/1/
sumber
Anda juga harus mempertimbangkan jenis-jenis objek yang dapat bertabrakan dengan wajar.
Misalnya pemain mungkin perlu diperiksa untuk tabrakan dengan segala sesuatu kecuali peluru sendiri. Namun musuh mungkin hanya perlu memeriksa terhadap peluru pemain. Peluru hampir pasti tidak perlu saling bertabrakan.
Untuk menerapkan ini secara efisien Anda mungkin ingin menyimpan daftar objek yang terpisah, satu per jenis objek.
sumber