Respon persegi panjang tabrakan

10

Saya mengalami kesulitan mendapatkan persegi panjang yang dapat dipindahkan untuk bertabrakan dengan lebih dari satu persegi panjang.

Saya menggunakan SFML dan memiliki fungsi praktis yang disebut intersectsyang mengambil 2 persegi panjang dan mengembalikan persimpangan. Saya memiliki vektor penuh persegi panjang yang saya ingin persegi panjang bergerak saya bertabrakan. Saya mengulang-ulang ini menggunakan kode berikut (p adalah persegi panjang moveble).

IsCollidingWithmengembalikan bool tetapi juga menggunakan SFML intersectsuntuk bekerja di persimpangan.

while(unsigned i = 0; i!= testRects.size(); i++){
   if(p.IsCollidingWith(testRects[i]){
        p.Collide(testRects[i]);
   }
}

dan Collide()kode aktual :

void gameObj::collide( gameObj collidingObject ){

 printf("%f %f\n", this->colliderResult.width, this->colliderResult.height);

if (this->colliderResult.width < this->colliderResult.height) {
    // collided on X
    if (this->getCollider().left < collidingObject.getCollider().left ) {
        this->move( -this->colliderResult.width , 0);
    }else {
        this->move( this->colliderResult.width, 0 );
    }

}

if(this->colliderResult.width > this->colliderResult.height){
    if (this->getCollider().top < collidingObject.getCollider().top ) {
        this->move( 0, -this->colliderResult.height);
    }else {     
        this->move( 0, this->colliderResult.height );
    }

}

dan IsCollidingWith()kodenya adalah:

bool gameObj::isCollidingWith( gameObj testObject ){
if (this->getCollider().intersects( testObject.getCollider(), this->colliderResult )) {
    return true;
}else {
    return false;
}

Ini berfungsi dengan baik ketika hanya ada 1 Rectdi tempat kejadian. Namun, ketika ada lebih dari satu Rectitu menyebabkan masalah ketika berolahraga 2 tabrakan sekaligus.

Adakah cara untuk menangani hal ini dengan benar? Saya telah mengunggah video ke youtube untuk menunjukkan masalah saya. Konsol di ujung kanan menunjukkan lebar dan tinggi persimpangan. Anda dapat melihat di konsol bahwa ia mencoba menghitung 2 tabrakan sekaligus, saya pikir di sinilah masalahnya.

Akhirnya, gambar di bawah ini tampaknya menggambarkan masalah saya dengan baik:

persegi panjang bertabrakan dengan beberapa persegi panjang lainnya

Dotty
sumber
Tautan video rusak.
XiaoChuan Yu
Apakah colliderobjek dikembalikan dengan this->getCollider()diperbarui oleh this->move()??
XiaoChuan Yu
Bisakah Anda menambahkan beberapa informasi lebih lanjut? Apa sebenarnya masalahnya? Video YouTube tampaknya menunjukkan perilaku yang dapat diprediksi, dan hanya ada satu persegi panjang lain di layar.
Wackidev

Jawaban:

3

Gambar Anda menggambarkan salah satu dari banyak masalah dengan mencoba menggunakan bentuk cembung - terutama persegi panjang - untuk mensimulasikan permukaan datar seperti lantai. Algoritme menyebabkan karakter terjebak di tepi bagian dalam bentuk yang membentuk lantai.

Perbaikan sederhana untuk itu adalah untuk memeriksa hanya tabrakan vertikal, perbaiki itu, lalu periksa lagi untuk tabrakan horizontal. Kecuali Anda jatuh dan mencoba untuk meluncur ke bawah dinding, dalam hal ini Anda ingin memeriksa tabrakan horizontal terlebih dahulu. Bagaimana Anda tahu kapan harus memeriksa yang pertama? Anda bisa melakukannya berdasarkan komponen kecepatan Anda yang lebih besar (jika gerakan horizontal lebih besar, periksa tumbukan vertikal terlebih dahulu, atau periksa tumbukan horizontal).

Apa yang bisa lebih sederhana - dan lebih banyak performant - adalah menghasilkan daftar edge untuk dunia Anda. Yaitu, untuk kotak Anda yang membentuk lantai, atur bendera yang menunjukkan bahwa hanya tepi atas mereka yang benar-benar dapat collidable, dan kemudian abaikan tabrakan dengan tepi lainnya. Anda tidak akan dapat menggunakan rutin tabrakan SFML untuk itu, tetapi jujur ​​saja tabrakan kotak mungkin adalah bit kode termudah yang pernah Anda tulis dalam sebuah game. Teknik ini bekerja sangat baik jika dunia Anda sejajar dengan kisi. Saya akan memeriksa tutorial Metanet yang sangat baik (http://www.metanetsoftware.com/technique.html/) untuk teknik itu.

Anda akan mengalami banyak masalah saat mencoba membangun game platformer 2D sederhana seperti Anda. Sejauh ini, sumber daya terbaik yang pernah saya lihat latel untuk itu adalah yang berikut, yang harus Anda baca, dan kemudian baca lagi:

http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/

Sean Middleditch
sumber
1

Mungkin solusi sederhana adalah untuk memeriksa tabrakan dengan setiap persegi panjang dan bergerak mundur, dalam arah gerakan yang berlawanan, sampai tidak ada tabrakan yang terdeteksi. Jika itu menyelesaikan masalah, implementasinya juga harus cukup sederhana.

arex
sumber
+1, saya benar-benar menulis tentang itu di sini: gamedev.stackexchange.com/questions/38252/…
Markus von Broady
0

Saya tidak berpikir memiliki 2 tabrakan dihitung adalah masalah, hanya masalah kinerja. Agar tabrakan ditangani dengan benar, mungkin harus diuji dua kali. Menggunakan diagram Anda berpikir jika A diuji terhadap B pertama, maka perlu diuji terhadap kotak lain juga, dan mungkin bertabrakan dengan yang lain.

Semoga itu bermanfaat?

james82345
sumber
0

Ini sebenarnya bukan metode yang optimal, Anda harus mencoba menentukan waktu paling awal kapan atau titik pertama di sepanjang jalur objek bergerak di mana tabrakan terjadi dan memindahkan objek ke posisi itu (atau posisi pada waktu yang dihitung), mencoba untuk benar berdasarkan pada posisi penetrasi setelah gerakan sangat bermasalah, tetapi Anda dapat menggunakan proses Anda saat ini dengan perubahan kecil. Terus periksa tabrakan sampai tidak ada.

bool collided = true;
while(collided) {
   collided = false
   while(unsigned i = 0; i!= testRects.size(); i++){
      if(p.IsCollidingWith(testRects[i]){
         collided = true
         p.Collide(testRects[i]);
      }
   }
}

Perhatikan bahwa ada situasi di mana ini akan mengarah ke Infinite Loop (pikirkan situasi di mana memindahkan kotak keluar dari tabrakan menghasilkan koleksi lain, dan memindahkan kotak keluar dari tabrakan itu memindahkannya kembali ke posisi bertabrakan yang sama seperti sebelumnya)

Matthew R
sumber