Sunting: Komentar OP telah skeptis tentang efisiensi cek terikat lingkaran negatif yang disarankan untuk meningkatkan algoritma agar dapat memeriksa apakah titik 2D sewenang-wenang terletak di dalam persegi panjang yang diputar dan / atau bergerak. Mengotak-atik mesin game 2D saya (OpenGL / C ++), saya melengkapi jawaban saya dengan memberikan tolok ukur kinerja algoritma saya terhadap algoritma point-in-rectangle-check OP saat ini (dan variasi).
Saya awalnya menyarankan untuk meninggalkan algoritma di tempat (karena hampir optimal), tetapi menyederhanakan melalui logika permainan belaka: (1) menggunakan lingkaran pra-diproses di sekitar persegi panjang asli; (2) melakukan pengecekan jarak dan jika titik terletak di dalam lingkaran yang diberikan; (3) gunakan OP atau algoritma langsung lainnya (saya sarankan algoritma isLeft seperti yang disediakan dalam jawaban lain). Logika di belakang saran saya adalah bahwa memeriksa apakah suatu titik di dalam lingkaran jauh lebih efisien daripada pemeriksaan batas dari persegi panjang yang diputar atau poligon lain.
Skenario awal saya untuk uji benchmark adalah menjalankan sejumlah besar titik yang muncul dan menghilang (yang posisinya berubah di setiap loop permainan) di ruang terbatas yang akan diisi dengan sekitar 20 kotak yang berputar / bergerak. Saya telah menerbitkan video ( tautan youtube ) untuk tujuan ilustrasi. Perhatikan parameternya: jumlah titik, angka, atau persegi yang muncul secara acak. Saya akan melakukan benchmark dengan parameter berikut:
OFF : Algoritma langsung seperti yang disediakan oleh OP tanpa pemeriksaan negatif batas lingkaran
ON : Menggunakan lingkaran per-diproses (batas) di sekitar persegi panjang sebagai pemeriksaan pengecualian pertama
ON + Stack : Membuat batas lingkaran saat run-time di dalam loop pada stack
ON + Kuadrat Jarak : Menggunakan jarak kuadrat sebagai optimasi lebih lanjut untuk menghindari pengambilan algoritma kuadrat yang lebih mahal (Pieter Geerkens).
Berikut ini adalah ringkasan dari berbagai kinerja algoritma yang berbeda dengan menunjukkan waktu yang diperlukan untuk beralih melalui loop.
Sumbu x menunjukkan peningkatan kompleksitas dengan menambahkan lebih banyak titik (dan dengan demikian memperlambat loop). (Misalnya, pada 1000 titik yang muncul secara acak memeriksa dalam ruang tertutup dengan 20 persegi panjang, loop berulang dan memanggil algoritme 20000 kali.) Sumbu-y menunjukkan waktu yang diperlukan (ms) untuk menyelesaikan seluruh loop menggunakan resolusi tinggi timer kinerja. Lebih dari 20 ms akan bermasalah untuk game yang layak karena tidak akan mengambil keuntungan dari fps tinggi untuk menginterpolasi animasi yang halus dan permainan mungkin muncul 'kasar' di kali.
Hasil 1 : Algoritma terikat terikat pra-diproses dengan cek negatif cepat dalam loop meningkatkan kinerja sebesar 1900% dibandingkan dengan algoritma biasa (5% dari waktu loop asli tanpa cek). Hasilnya memegang kira-kira sebanding dengan jumlah iterasi dalam satu loop, sehingga tidak masalah jika kita memeriksa 10 atau 10000 poin yang muncul secara acak. Dengan demikian, dalam ilustrasi ini orang dapat meningkatkan jumlah objek dengan aman hingga 10rb tanpa merasakan kehilangan kinerja.
Hasil 2 : Telah dikomentari oleh komentar sebelumnya bahwa algoritma mungkin lebih cepat tetapi intensif memori. Namun, perhatikan bahwa menyimpan pelampung untuk ukuran lingkaran pra-proses hanya membutuhkan 4 byte. Ini seharusnya tidak menimbulkan masalah nyata kecuali OP berencana untuk menjalankan 100000 objek secara bersamaan. Alternatif dan pendekatan memori efisien adalah untuk menghitung ukuran lingkaran maksimum pada tumpukan dalam loop dan membiarkannya keluar dari ruang lingkup dengan setiap iterasi dan dengan demikian praktis tidak menggunakan memori untuk beberapa harga kecepatan yang tidak diketahui. Memang, hasilnya menunjukkan bahwa pendekatan ini memang lebih lambat daripada menggunakan ukuran lingkaran pra-diproses, tetapi masih menunjukkan peningkatan kinerja yang cukup besar sekitar 1150% (yaitu 8% dari waktu pemrosesan asli).
Hasil 3 : Saya lebih meningkatkan algoritma hasil 1 dengan menggunakan jarak kuadrat bukan jarak yang sebenarnya dan dengan demikian mengambil operasi root kuadrat komputasi mahal. Ini hanya sedikit meningkatkan kinerja (2400%). (Catatan: Saya juga mencoba tabel hash untuk array pra-diproses untuk perkiraan akar kuadrat dengan hasil yang serupa tetapi sedikit lebih buruk)
Hasil 4 : Saya selanjutnya memeriksa bergerak / bertabrakan persegi panjang di sekitar; Namun, ini tidak mengubah hasil dasar (seperti yang diharapkan) karena pemeriksaan logis pada dasarnya tetap sama.
Hasil 5 : Saya memvariasikan jumlah persegi panjang dan menemukan bahwa algoritma menjadi lebih efisien semakin sedikit ruang crowdy diisi (tidak ditampilkan dalam demo). Hasilnya juga agak diharapkan, karena probabilitas berkurang untuk titik muncul dalam ruang kecil antara lingkaran dan batas-batas objek. Pada ekstrem yang lain, saya mencoba untuk menambah jumlah persegi panjang juga 100 dalam ruang kecil yang sama DAN memvariasikannya secara dinamis dalam ukuran saat run time di dalam loop (sin (iterator)). Ini masih berkinerja sangat baik dengan peningkatan kinerja sebesar 570% (atau 15% dari waktu loop asli).
Hasil 6 : Saya menguji algoritma alternatif yang disarankan di sini dan menemukan perbedaan yang sangat kecil tetapi tidak signifikan dalam kinerja (2%). Algoritme IsLeft yang menarik dan lebih sederhana memiliki kinerja yang sangat baik dengan peningkatan kinerja sebesar 17% (85% dari waktu perhitungan awal), tetapi tidak ada efisiensi algoritma pengecekan negatif yang cepat.
Maksud saya adalah pertama-tama mempertimbangkan desain ramping dan logika game, terutama ketika berhadapan dengan batas dan peristiwa tabrakan. Algoritma OPs saat ini sudah cukup efisien dan optimasi lebih lanjut tidak sepenting mengoptimalkan konsep yang mendasarinya sendiri. Selain itu, baik untuk mengomunikasikan ruang lingkup dan tujuan permainan, karena efisiensi suatu algoritma sangat tergantung pada mereka.
Saya menyarankan untuk selalu berusaha melakukan tolok ukur algoritme yang kompleks selama tahap desain game karena hanya dengan melihat kode biasa mungkin tidak mengungkapkan kebenaran tentang kinerja run-time aktual. Algoritme yang disarankan mungkin tidak diperlukan di sini, jika, misalnya, seseorang hanya ingin menguji apakah kursor mouse berada di dalam persegi panjang atau tidak, atau, ketika sebagian besar objek sudah menyentuh. Jika sebagian besar titik memeriksa berada dalam persegi panjang, algoritme akan kurang efisien. (Namun, maka akan mungkin untuk menetapkan batas 'lingkaran dalam' sebagai pemeriksaan negatif sekunder.) Pemeriksaan batas lingkaran / bola sangat berguna untuk setiap deteksi tabrakan yang layak dari sejumlah besar objek yang secara alami memiliki ruang di antaranya. .
Rec Points Iter OFF ON ON_Stack ON_SqrDist Ileft Algorithm (Wondra)
(ms) (ms) (ms) (ms) (ms) (ms)
20 10 200 0.29 0.02 0.04 0.02 0.17
20 100 2000 2.23 0.10 0.20 0.09 1.69
20 1000 20000 24.48 1.25 1.99 1.05 16.95
20 10000 200000 243.85 12.54 19.61 10.85 160.58