Bagaimana cara menangani benturan sudut dalam 2D?

22

Saya sedang menulis game XNA 2d dari atas ke bawah. Sejak pertama kali saya mencoba menulis fisika dan tabrakan sendiri untuk mempelajarinya.

Setiap kali karakter sprite pemain saya mencoba untuk pindah ke posisi di mana batas-batasnya bersinggungan dengan tepi dinding, saya menemukan sudut pantulan (sudut insiden = sudut pantulan) dan saya membuat pemain memantul dari dinding dan menghindari tabrakan .

Saya mengalami kesulitan mencari tahu bagaimana menghadapi situasi sprite saya berpotongan dengan dua tepi dinding secara bersamaan meskipun misalnya menyentuh sudut.

tabrakan sudut

Kode saya saat ini memberi tahu saya bahwa dua tepi dinding telah berpotongan tetapi tidak pada tepi mana yang akan mengenai pertama dan oleh karena itu tepi mana yang terpental.

Apa tes matematika untuk memilih sisi mana yang harus dipantulkan? Jelas terlihat ketika melihatnya, tetapi saya berjuang untuk mengetahui tes matematika untuk itu.

TerryB
sumber
Terima kasih Tetrad. Saya melihat yang satu itu tapi kelihatannya bola akan berperilaku berbeda dengan masalah persegi panjang saya. Dalam kasus yang digambarkan di atas, sprite persegi panjang akan mengenai tepi bawah dinding dan memantul darinya. Tepi samping dinding tidak akan pernah masuk ke persamaan. Saya hanya tidak tahu bagaimana mengungkapkannya dalam kode dan membuat keputusan itu.
TerryB

Jawaban:

9

Jika Anda menghitung seberapa jauh ke Walldalam Player Spritetelah pindah, Anda mungkin bisa mendasarkan pada delta x dan koordinat y dari sudut-sudut yang berpotongan. Saya harap itu masuk akal, saya tidak bisa memikirkan cara yang lebih baik untuk mengatakannya.

Jadi, misalnya, jika Anda melihat diagram Anda. Ambil xnilai sudut kiri atas Player Sprite(setelah pindah), dan kurangi xnilai sudut kanan bawah Wall. Lakukan hal yang sama untuk ynilai - nilai dan kemudian lihat mana yang lebih besar. Kuncinya adalah bahwa jika satu lebih besar dari yang lain, Player Spritemungkin berpotongan di sisi itu.

Berikut adalah contoh gambar (ini adalah subbagian dari gambar Anda dengan baris saya sendiri ditambahkan):

contoh persimpangan

Sekarang, Anda lihat di sini bahwa garis biru lebih besar dari garis hijau. Dalam hal ini garis biru juga berada di sisi yang Player Spritediharapkan memantul.

Jika kedua nilai sama, mereka menekan tepat di sudut.

Sekarang, ada sedikit masalah dengan melakukannya dengan cara ini. Jika Player Spriteperjalanan sangat cepat atau tabrakan sangat dekat dengan sudut, ada kemungkinan bahwa Player Spritemungkin pergi lebih jauh ke Wallarah yang salah. Dalam hal ini Anda mungkin harus memeriksa kecepatan objek bergerak. (Lihat jawaban Nathan Reed .)

Catatan: Saya pikir saya pada dasarnya mencoba untuk menggambarkan deteksi tabrakan SAT yang @Blau sebutkan, tapi saya sudah menghabiskan waktu yang lama untuk menulis ini jadi saya akan mempostingnya. Semoga ini bisa membantu Anda.

Richard Marskell - Drackir
sumber
Drackir terima kasih! Dan saya kira jika dinding saya diputar relatif terhadap sprite itu agak rumit tetapi prinsip yang sama berlaku. Cari vektor perpindahan panjang minimum yang berarti sprite tidak akan bertabrakan dengan dinding. Kemudian gunakan dinding yang normal untuk vektor itu sebagai salah satu untuk bangkit.
TerryB
@TerryB - Rotasi menambahkan sedikit kerumitan padanya. Anda mungkin ingin membaca tentang kotak bounded aligned (AABB). Pada dasarnya, Anda masih menggunakan prinsip yang sama seperti di atas dengan menguji kotak terkecil yang cocok dengan objek yang diputar, tetapi yang kapaknya disejajarkan dengan sumbu cartesian. Bayangkan jika Anda memiliki kotak dan Anda memutarnya 45 derajat untuk membuatnya menjadi berlian. Menghitung tabrakan itu akan sulit dan mahal, jadi pertama-tama periksa untuk melihat apakah objek itu bahkan dekat dengan menggunakan AABB yang akan menjadi kotak di mana setiap titik berlian menyentuh setiap sisi di tengah.
Richard Marskell - Drackir
Kemudian, ketika Anda tahu sudah dekat, Anda dapat melakukan perhitungan yang lebih mahal untuk melihat apakah mereka berpotongan pada sudut (yang mungkin harus menjadi pertanyaan lain sama sekali :)).
Richard Marskell - Drackir
1
-1 karena perpindahan minimum tidak selalu memberikan jawaban yang benar untuk "tepi mana yang bertabrakan terlebih dahulu"; lihat jawaban saya.
Nathan Reed
@NathanReed - Itulah sebabnya saya menyebutkan memeriksa kecepatan di paragraf "Sekarang, ada sedikit masalah dengan melakukannya dengan cara ini".
Richard Marskell - Drackir
15

Perpindahan minimum tidak selalu memberikan jawaban yang tepat untuk sisi mana yang pertama kali mengenai. Pertimbangkan kasus ini:

hal yang memecah algoritma pemindahan terpendek

Ini terjadi ketika kecepatannya cukup tinggi sehingga blok bergerak agak jauh selama satu frame. Untuk mendeteksi dengan benar tepi mana yang pertama kali mengenai, Anda harus mengatur persamaan linier untuk dipecahkan pada saat tabrakan dengan masing-masing tepi. Dalam hal ini dijelaskan dalam diagram OP, persamaan yang relevan adalah:

timeXCollision = (player.left - wall.right) / -player.velocity.x
timeYCollision = (wall.bottom - player.top) / player.velocity.y

(Ini mengasumsikan sistem koordinat X-kanan, Y-up.) Secara umum, Anda harus menggunakan tanda-tanda pemain. Komponen X dan Y tingkat untuk menentukan pasangan tepi mana yang perlu diuji. Bagaimanapun, setelah Anda menghitung waktu tumbukan, yang lebih awal dari keduanya adalah tumbukan yang perlu Anda tangani.

Nathan Reed
sumber
1
Bisakah Anda memberikan contoh tentang bagaimana dua variabel Anda dapat diimplementasikan?
BjarkeCK
1

Anda membutuhkan SAT Collision Detection

Pada dasarnya Anda perlu mencari vektor perpindahan minimum yang dikurangi ke salah satu objek agar tidak berpotongan.

Dalam gambar Anda, perpindahan minimum adalah segmen oranye.

masukkan deskripsi gambar di sini

Blau
sumber
4
-1 karena perpindahan minimum tidak selalu memberikan jawaban yang benar untuk "tepi mana yang bertabrakan terlebih dahulu"; lihat jawaban saya.
Nathan Reed
siapa yang bertanya itu?
Blau
Pertanyaannya adalah menanyakan itu. "Kode saya saat ini memberi tahu saya bahwa dua tepi dinding telah berpotongan tetapi tidak pada tepi mana yang akan mengenai pertama dan oleh karena itu tepi mana yang terpental."
Nathan Reed
pertama? masalahnya bukan apa yang pertama, itu bertabrakan dengan dua sisi pada saat yang sama, ... masalahnya adalah tepi mana yang terpental, Anda telah memilih satu metode yang baik untuk Anda, saya telah memilih metode yang baik untuk saya, keduanya valid
Blau
1
Jika Anda ingin membuat keputusan desain untuk membiarkan benda-benda melewati satu sama lain seperti itu, seolah-olah mereka bulat atau miring di sudut, itu keputusan Anda, dan mungkin merupakan hal yang tepat untuk gameplay Anda. Tapi saya tidak berpikir pertanyaannya adalah tentang keputusan desain; itu bertanya secara matematis bagaimana memantulkan persegi panjang yang selaras sumbu satu sama lain. Ini bukan masalah interpretasi; masalah matematika ini memiliki jawaban yang jelas dan benar untuk sisi mana memantul.
Nathan Reed
0

Menjawab pertanyaan serupa di sini

Anda mungkin ingin mempertimbangkan untuk memeriksa posisi sebelumnya-

Misalnya: jika sisi kiri Anda sebelumnya di sebelah kanan sisi kanan mereka dan Anda bertabrakan, maka telah terjadi tabrakan di sebelah kanan.

Jika Anda melakukan ini, cukup atasi tabrakan sumbu y, periksa apakah Anda bertabrakan dengan sesuatu, lalu atasi tabrakan sumbu x.

ultifinitus
sumber