Bagaimana menemukan sel-sel jaringan 2D disapu oleh lingkaran yang bergerak?

9

Saya membuat game berdasarkan grid 2D, dengan beberapa sel lumayan dan beberapa tidak. Objek dinamis dapat bergerak terus menerus, terlepas dari kisi, tetapi perlu bertabrakan dengan sel yang tidak bisa dilewati.

Saya menulis sebuah algoritma untuk melacak sinar pada grid, yang memberi saya semua sel yang bersilangan. Namun, objek sebenarnya tidak berukuran titik; Saat ini saya mewakili mereka sebagai lingkaran. Tetapi saya tidak dapat menemukan algoritma yang efektif untuk melacak lingkaran yang bergerak. Ini gambar yang saya butuhkan: masukkan deskripsi gambar di sini

Angka-angka menunjukkan dalam urutan apa lingkaran bertabrakan dengan sel-sel kisi. Adakah yang tahu algoritma untuk menemukan tabrakan ini? Lebih disukai dalam C #.

Perbarui Lingkaran bisa lebih besar dari sel kotak tunggal.

Sudahlah
sumber
mmh mengapa 3 bertabrakan SEBELUM 4?
FxIII
@FxIII Saya benar-benar memindahkan lingkaran dalam gambar, dan menyentuh 3 sebelum 4. Hanya nyaris, tapi masih sebelumnya.
Nevermind

Jawaban:

6

Saya pikir gambar Anda sedikit menyesatkan karena Anda memilih untuk menggambar garis dari titik pada lingkaran yang bersinggungan dengan arah bergerak Anda. Saya bisa melihat bahwa tabrakan ke tepi kisi Anda bahagia ketika titik TOP dan LEFT dari lingkaran Anda menyentuh tepi.

Biarkan C menjadi pusat Anda dan r jari-jari sehingga P ' = C + ( r , 0) dan P " = C + (0, r).

Jika D adalah vektor arah Anda (versor), Anda memiliki dua baris:

R '= D · t + P' ,

R "= D · t + P"

Anda harus menemukan persimpangan garis-garis tersebut dengan garis persamaan:

y = i dan y = i yang merupakan tepi dari grid Anda!

Solusinya mudah karena Anda hanya perlu mempertimbangkan komponen x atau y dari R 'dan R ". Anda akan menemukan t untuk setiap bagian, dan poin untuk thoose t , cukup urutkan titik tersebut dengan t dan Anda sudah selesai.

Saya percaya Anda dapat dengan mudah mengatakan sel apa yang dipukul jika Anda tahu titik persimpangan.

Ini berfungsi jika r <1 (lebar dan tinggi sel).

Ini bekerja juga untuk kasus-kasus lain hanya melakukan beberapa pertimbangan P ' dan P " . Kami memilih TOP dan KIRI karena arah, BOTTOM dan KANAN harus dipertimbangkan untuk arah yang berlawanan, Anda mengerti mengapa.

Sekarang lihat gambar ini: lingkaran besar

Lingkaran lebih besar dari satu sel dan kami mengira itu akan arah yang sama dengan gambar Anda. P1 adalah titik pertama yang akan menyentuh, P2 adalah yang kedua, P3 tidak berguna karena berada di bagian bawah. Yang perlu Anda lakukan adalah melempar sinar dari P1 dan P2 seperti yang kita lihat sebelumnya dan melakukan hal yang sama untuk garis vertikal.

Secara umum Anda akan memiliki titik awal lainnya bersama dengan TOP dan yang KIRI dari mana menembakkan sinar Anda, semakin besar lingkaran Anda, semakin banyak sinar yang harus dilemparkan.

Sejujurnya beberapa Anda dapat menghindari untuk menembak semua sinar melakukan pertimbangan geometris, tetapi itu dapat membuat hal-hal lebih sulit untuk dipahami.

FxIII
sumber
Ya, saya memikirkan P 'dan P "menunjuk sendiri, tetapi tidak tahu apa yang harus dilakukan ketika lingkaran lebih besar dari satu sel. Poin tambahan benar-benar masuk akal (dan saya jelas hanya perlu menambahkan sinar antara P' dan P ")
Nevermind
Pertimbangan geometris dapat dilakukan yang menyederhanakan perhitungan tetapi menggunakan implementasi dapat membawa Anda ke hasil yang sama dengan pengalaman.
FxIII
Apakah jelas bahwa Anda harus menguji garis grid horizontal dan vertikal secara terpisah?
FxIII
Saya pikir Anda juga harus memeriksa ketika lingkaran menutupi simpul grid, karena lingkaran akan bertabrakan dengan sel yang berdekatan secara diagonal di sudutnya tetapi itu tidak harus menjadi titik atas / kiri / bawah / paling kanan pada lingkaran yang menyentuhnya terlebih dahulu. (dan Anda akan mendeteksi tabrakan terlalu dini.) Contoh: kotak 3,4,5 pada diagram contoh dalam pertanyaan. Mereka dipukul berurutan (3 kemudian 4 kemudian 5) tetapi algoritma Anda akan mendeteksi 4 & 5 secara bersamaan.
finnw
@ finnw mereka menyentuh secara bersamaan hanya jika cicle melakukan perjalanan tepat ke arah bisector.
FxIII
1

Jika Anda ingin menggunakan algoritme tabrakan-ray Anda, Anda dapat memilih delapan titik pada setiap lingkaran (dengan kenaikan 45 derajat, selaras dengan kisi-kisi persegi Anda), dan menggunakan tabrakan-ray antara titik-titik yang sesuai (yaitu, dari atas satu lingkaran ke atas yang lain). Penyatuan semua tabrakan sinar ini adalah seluruh set sel yang berpotongan.

Anda mungkin dapat memperbaiki ini sedikit - misalnya dengan menggunakan segmen garis dari pusat satu lingkaran ke pusat yang lain, tetapi diperluas di kedua sisi dengan jari-jari lingkaran, serta segmen garis paralel pada kedua sisi di ujung lingkaran.

TreDubZedd
sumber
8 sinar mungkin akan menjamin semua persimpangan, tetapi mereka tidak akan memberikannya dalam urutan yang benar. Dan untuk tabrakan saya perlu memesan, bukan hanya daftar sel.
Nevermind
Tambahkan algoritme tabrakan-ray Anda untuk mempertahankan nilai-t untuk setiap tabrakan. Saat Anda mendapatkan penyatuan sel, Anda bisa mengurutkan pada nilai-t untuk mendapatkan urutan yang benar.
TreDubZedd
Tetapi bagaimana saya bisa membandingkan nilai-t dari berbagai sinar?
Nevermind
Jika Anda selalu berasal dari lingkaran yang sama, titik persimpangan Anda akan menjadi jarak dari lingkaran itu. Ketika Anda datang ke sel yang sudah Anda lihat, jika nilai t dari tumbukan saat ini lebih kecil dari yang sebelumnya, gunakan ... jika tidak, buang persimpangan (menjaga yang asli).
TreDubZedd
1
Anda mungkin bisa lolos hanya dengan dua sinar di sisi lingkaran yang tegak lurus dengan gerakan, lalu Anda bisa melihat ubin mana yang terkena sinar dan Anda bisa memeriksa sisanya untuk melihat apakah pusatnya jatuh di antara dua sinar. Satu-satunya hal yang harus dilewatkan adalah hal-hal yang bertabrakan di lingkaran awal atau akhir tetapi itu hanya dua lingkaran dan dapat ditangani dengan mudah. Mungkin sedikit lebih lambat dari delapan sinar, saya tidak yakin; tetapi Anda tidak perlu mengukur angka berdasarkan ukuran lingkaran.
Lunin
1

Saya tidak mengatakan ini analogi yang sempurna, tetapi Anda mungkin berpikir tentang algoritma garis Bresenham . Modifikasi algoritme ini atau salah satu ekstensi mungkin membantu, terutama jika Anda memasangkannya dengan beberapa posting dan komentar lainnya. Biasanya, algoritme ini tidak berkaitan dengan pemesanan, tetapi saya akan berpikir bahwa Anda dapat menambahkannya secara sepele.

Ryan
sumber
Saya juga memikirkan hal ini, tetapi menurut saya, ini bukan algoritma yang tepat. Bresenham memilih hanya satu piksel, ia membutuhkan semua. Dan akan sulit untuk mengadaptasi bresenham ke lingkaran insted hanya satu piksel.
zacharmarz
Pelacak ray yang saya gunakan sebenarnya agak agak berdasarkan algoritma Bresenham. Saya mengalami kesulitan untuk menggeneralisasikannya dari garis tipis menjadi garis "gemuk", khususnya yang tersapu lingkaran.
Nevermind