Kelas tabrakan top-down yang dapat digunakan kembali

8

Saya baru-baru ini mengambil monogame dan sedang mengerjakan permainan top down sederhana untuk memulai dan mempelajari dasar-dasarnya.
Saya mendapatkan pergerakan dan rotasi untuk mengikuti mouse, tetapi saya terjebak dengan tabrakan.
Apa yang ingin saya ketahui, pada dasarnya, adalah dua hal:

  1. Apa cara terbaik untuk menangani tabrakan? Saya tahu bahwa Rectangle.Intersects(Rectangle1, Rectangle2)mengembalikan persegi panjang yang tumpang tindih, tetapi, karena gerakan di atas ke bawah adalah pada sumbu x / y saya ingin tahu di mana tabrakan terjadi sehingga saya dapat membuat semacam "geser dinding" di mana pemain tidak mendapatkan terjebak di dinding.
    Apakah memeriksa koordinat pemain x / y terhadap koordinat objek padat, lalu melempar pemain ke posisi sebelumnya jika ia memasuki batas objek padat benar-benar pendekatan terbaik? Apa yang kamu sarankan?
  2. Apa cara terbaik untuk menerapkan tabrakan ke semua padatan, npc, dll.? Saat ini saya sedang berpikir untuk membuat gameObjectkelas dimana semua objek akan mewarisi dan hanya menangani tabrakan di sana.

Terima kasih telah membaca dan berharap seseorang dapat memberi saya beberapa tips.

Eliah John
sumber
Untuk beberapa pemikiran tentang pertanyaan kedua Anda, lihat jawaban ini tentang arsitektur game .
Andrew Russell

Jawaban:

9

Umumnya cara sebagian besar mesin fisika menangani masalah ini adalah dengan memisahkan objek yang berpotongan .


Jadi jika objek Anda diwakili oleh persegi panjang (juga dikenal sebagai "Axis Aligned Bounding Boxes"), dan mereka bertabrakan pada bingkai tertentu seperti:

Tabrakan


Anda kemudian akan mengukur jumlah interpenetrasi pada setiap sumbu. Kemudian pilih sumbu dengan jumlah interpenetrasi terkecil, dan pisahkan objek di sepanjang sumbu itu.

Terpisah


Anda kemudian akan mendaftarkan ini sebagai "tabrakan" dan menerapkan dinamika yang sesuai.

Misalnya, jika Anda ingin meluncur di sepanjang dinding, Anda hanya perlu nol-kecepatan pada sumbu yang Anda pisahkan (sumbu X, pada ilustrasi di atas), meninggalkan kecepatan pada sumbu lain saja.

Tapi Anda juga bisa menerapkan gesekan, atau membuat benda memantul.


Berikut ini adalah tutorial interaktif luar biasa yang menunjukkan cara melakukan ini dengan lebih detail.

Meskipun, jika Anda akan pergi jauh ke jalan ini (lebih dari tabrakan AABB sederhana), Anda mungkin ingin mempertimbangkan untuk menggunakan mesin yang ada seperti Farseer Physics .


Akhirnya, catatan implementasi (jika Anda tidak menggunakan rute Farseer): Rectanglemenggunakan intnilai-nilai, yang sebenarnya tidak tepat untuk melakukan fisika dalam banyak kasus. Pertimbangkan untuk membuat AABBkelas sendiri yang menggunakan kelas float.

Pertanyaan kedua Anda dijawab dengan baik oleh jawaban lama saya tentang arsitektur game di sini , jadi saya tidak akan mengulanginya di sini.

Andrew Russell
sumber
Mungkin ada sesuatu yang tidak saya mengerti, tetapi bukankah pendekatan ini cacat? Saya telah mengilustrasikan masalah di sini: jmp.sh/jEW2lvR Ini akan menghasilkan beberapa perilaku aneh di kali.
BjarkeCK
@JarkeCK: Ya, Anda perlu melakukan pekerjaan ekstra untuk menangani kasus seperti itu. Saya tidak cukup berpengalaman untuk sepenuhnya menjelaskan cara menanganinya dengan benar (saya hanya menggunakan Farseer dan menyebutnya sehari). Mungkin lihat "Bagian 5" dari tautan ini .
Andrew Russell
1

1: Saya telah bekerja pada permainan aksi top-down yang relatif sederhana juga, dan setelah seminggu (-s?) Perjuangan, saya akhirnya menggunakan semacam pendekatan langkah-demi-langkah untuk mendeteksi dan merespons tabrakan. Alasan utama adalah bahwa menggunakan jumlah interpenetrasi terpendek akan dalam beberapa kasus menghasilkan "teleportasi" ke posisi baru bahwa objek bergerak tidak di sebelumnya.

jadi, ketika suatu objek ingin bergerak,

  1. Saya membuat kotak pembatas objek pada posisi objek + moveAmount vektor, membuat semacam kotak pembatas target
  2. kemudian saya centang kotak target bounding ini untuk setiap persimpangan dengan objek game, ubin, dll. jika ada, saya menambahkannya ke daftar baru, yang menampung semua potensi tabrakan untuk frame saat ini
  3. jika tidak ada persimpangan, objek bergerak. tetapi jika ada persimpangan,
  4. Saya membagi gerakan yang diinginkan menjadi "langkah". kemudian saya menjalankan loop untuk jumlah langkah yang saya miliki. setiap langkah memindahkan objek hanya untuk 1 piksel dalam arah x dan y.
  5. untuk setiap langkah saya memeriksa setiap posisi baru yang diproyeksikan untuk tabrakan, jika tidak ada, saya menambahkan vektor langkah untuk vektor bergerak akhir.
  6. jika ada tabrakan (berpotongan mengembalikan true), saya membandingkan posisi sebelumnya (posisi pada langkah sebelumnya) objek bergerak dengan benda yang bertabrakan dengannya.
  7. tergantung pada posisi sebelumnya ini saya menghentikan gerakan sepanjang sumbu yang saling bertentangan (misalnya, jika objek bergerak datang pada objek bertabrakan dari atas, saya menetapkan nilai y dari vektor bergerak ke 0 dll).
  8. Saya ulangi ini untuk setiap langkah berturut-turut, menambahkan vektor langkah yang disesuaikan bersama-sama untuk membuat satu vektor moveAmount disesuaikan akhir yang dapat saya gunakan dengan aman untuk memindahkan objek tanpa terjadi tabrakan.

pendekatan ini keduanya memastikan bahwa objek "memantul" kembali untuk memperbaiki posisi sebelumnya dan memungkinkan untuk meluncur ke dinding, objek, apa pun.

2: Saya sendiri menggunakan kelas tabrakan statis yang dapat digunakan oleh apa pun. ia memegang metode deteksi tabrakan dan penyesuaian vektor, yang bisa disebut dengan apa saja. apakah metode ini dipanggil dari kelas game "master" atau oleh beberapa objek subclass tidak terlalu penting dalam kasus saya, karena kelas collision membuat daftar baru setiap frame untuk semua persegi panjang objek bergerak yang bersinggungan dengannya. persegi panjang ini mungkin berasal dari ubin, dekorasi, NPC, apa pun yang memiliki batas dan dapat disatukan, pada dasarnya. ini berarti bahwa kebutuhan mendasar untuk semua objek game yang dapat collidable adalah memiliki batas persegi panjang. jika mereka memilikinya, kelas tabrakan akan menangani sisanya.

Semoga ini bisa dimengerti.

AV
sumber
0

1: Saya berhasil menggunakan teknik untuk menyelesaikan ini: menggunakan kecepatan dan posisi Anda dapat menemukan tabrakan, dan beralih kembali sampai posisinya sangat dekat dengan titik tabrakan yang tepat.

Ini bukan bagian dari jawaban untuk pertanyaan pertama Anda, tetapi jika Anda memiliki banyak objek yang dapat saling bertabrakan, Anda harus menggunakan quadtrees untuk meningkatkan kinerja. Ada tutorial yang sangat bagus dengan banyak contoh di sini .

2: Saya selalu merekomendasikan Entity-Systems .

Filipe Borges
sumber