AABB 2D dan menyelesaikan beberapa tabrakan

8

Oke, jadi ini adalah masalah yang saya coba cari beberapa waktu. Mine adalah gim platformer 2D dengan dunia yang terdiri dari (biasanya) ubin bergerak dan sprite seluler, keduanya menggunakan AABBs untuk mewakili hitbox mereka. Game ini BUKAN berbasis grid karena beberapa komplikasi dengan memindahkan lapisan ubin.

Saya dapat mendeteksi tabrakan dan dengan mudah mengetahui kedalaman tabrakan. Saya menggunakan "metode poros dangkal" untuk menentukan cara untuk menyelesaikan tabrakan antara sprite dan ubin. Jika sprite lebih dalam secara horizontal daripada vertikal, arah penyelesaiannya adalah naik atau turun. Jika sprite lebih dalam secara vertikal daripada horizontal, arah penyelesaiannya adalah kiri atau kanan.

Diagram # 1

Ini cukup sederhana, dan itu bekerja dengan cukup baik. Yaitu, sampai Anda memiliki sprite bertabrakan dengan lebih dari satu ubin. Karena, menurut sifatnya, setiap tabrakan harus diperiksa secara terpisah, tabrakan yang berbeda mungkin memiliki arah yang berbeda untuk diselesaikan. Sebagai contoh, jika sprite mencoba berjalan melintasi deretan ubin, untuk satu bingkai mereka akan memotong ubin berikutnya seperti bahwa kedalaman horizontal lebih pendek daripada kedalaman vertikal. Ketika tabrakan mengatakan "tekad ke kiri", itu akan didorong kembali dan akan macet di sudut.

Diagram # 2

Saya telah merenungkan masalah ini berulang-ulang, untuk beberapa waktu, dan beberapa solusi telah datang kepada saya, tetapi semua memiliki kekurangan. Saya bisa menandai sisi-sisi tertentu sebagai tidak terjangkau, tetapi tanpa mesin berbasis grid, menentukan "tidak terjangkau" sangat rumit, terutama dengan memindahkan lapisan ubin selalu menjadi suatu kemungkinan.

Metode lain yang mungkin adalah memprediksi tumbukan sebelum terjadi dan "mengembalikan" gerakan ke titik tumbukan, saya kira, tapi saya tidak yakin bagaimana perhitungannya.

Saya merasa bahwa saya kehilangan sesuatu yang sangat jelas, terutama karena permainan dari tahun 80an telah menyelesaikan masalah ini.

Celarix
sumber
Anda bisa saja mengubah lokasi pemain berdasarkan ubin yang lebih dulu muncul di cek Anda
Chachmu

Jawaban:

6

Masalah

Masalahnya terletak pada metode resolusi tabrakan Anda. Metode Anda berjalan sebagai berikut:

  1. Pindahkan pemain.
  2. Periksa tabrakan.
  3. Tentukan kedalaman tumbukan terpendek.
  4. Atasi tabrakan.

Masalah dengan ini, adalah bahwa ia dapat dengan mudah menggerakkan pemain ke arah yang salah. Anda dapat melihat bagaimana ini dapat terjadi pada gambar di bawah:

Bug tabrakan

Karena pemain bergerak ke kanan, dan berada di atas tanah, Anda akan mengharapkan pemain untuk mendarat di atas tanah (dengan kotak hijau). Tetapi sebaliknya, ia didorong keluar dari tanah ke kiri (diwakili oleh kotak merah). Ini bisa menjadi masalah jika pemain mencoba untuk melompat dari satu platform ke platform lain, karena pemain mungkin akhirnya jatuh ke kematiannya karena kode tabrakan yang buruk.

Solusinya

Solusi untuk masalah ini sebenarnya cukup sederhana. Alih-alih menggunakan metode di atas, Anda menyelesaikan tabrakan seperti:

  1. Pindahkan pemain di sepanjang sumbu X.
  2. Periksa ubin bertabrakan.
  3. Selesaikan tabrakan X.
  4. Pindahkan pemain di sepanjang sumbu Y.
  5. Periksa ubin bertabrakan.
  6. Atasi tabrakan Y.

Sekarang saya harap Anda tidak membuang kode cek kedalaman Anda, karena Anda masih akan membutuhkannya untuk langkah 3 dan 6.

Untuk menyelesaikan tabrakan antar ubin pada salah satu dari dua sumbu (setelah memindahkan pemain), Anda harus terlebih dahulu mendapatkan kedalaman tabrakan. Anda kemudian mengambil kedalaman tabrakan, dan kurangi itu dari sumbu yang saat ini Anda periksa untuk tabrakan. Perhatikan bahwa kedalamannya harus negatif jika Anda bergerak ke kiri, sehingga pemain bergerak ke arah yang benar.

Dengan menggunakan metode ini, Anda tidak hanya tidak perlu khawatir tentang bug tabrakan seperti yang ada dalam skenario pada gambar di atas, tetapi metode ini juga dapat menangani tabrakan dengan beberapa ubin.

Kode contoh:

void move(velocity)
{
    top = player.y / TILE_HEIGHT;
    bottom = top + (player.height / TILE_HEIGHT);
    left = player.x / TILE_WIDTH;
    right = left + (player.width / TILE_WIDTH);

    // Check X

    player.x += velocity.x;
    player.updateAABB();
    for(int tx = left - 1; tx <= right + 1; tx++)
    {
        for(int ty = top - 1; ty <= bottom + 1; ty++)
        {
            aabb = world.getTileAABB(tx, ty);
            if(aabb.collidesWith(player.aabb))
            {
                depth = player.aabb.getXDepth(aabb);
                player.x -= depth;
            }
        }
    }

    // Now check Y

    player.y += velocity.y;
    player.updateAABB();
    for(int tx = left - 1; tx <= right + 1; tx++)
    {
        for(int ty = top - 1; ty <= bottom + 1; ty++)
        {
            aabb = world.getTileAABB(tx, ty);
            if(aabb.collidesWith(player.aabb))
            {
                depth = player.aabb.getYDepth(aabb);
                player.y -= depth;
            }
        }
    }

    player.updateAABB();
}
Lisol
sumber
Menarik, tapi saya masih melihat masalah. Dalam skenario kedua saya, sprite bertabrakan dengan deretan ubin. Jika saya memeriksa tabrakan X terlebih dahulu, akan ada satu deteksi yang salah dalam skenario itu, dan itu masih akan diselesaikan dengan tidak benar.
Celarix
@Celarix Skenario kedua tidak boleh terjadi karena Anda tidak hanya memeriksa sumbu X terlebih dahulu, Anda juga harus bergerak terlebih dahulu. Sprite tidak akan pernah berada di deretan ubin, karena uji tabrakan Y dari gerakan sebelumnya akan mencegah Anda bertabrakan dengan deretan ubin seperti itu. Pastikan tabrakan selalu diselesaikan dengan benar. Saya pernah mengalami beberapa masalah yang disebabkan oleh fakta bahwa saya menggunakan floats untuk menyimpan koordinat saya. Jadi itu menyebabkan getaran. Solusinya adalah memutari coord ketika saya selesai menyelesaikan tabrakan.
Lysol
Anda benar, dan saya pikir ini mungkin solusi untuk masalah saya selama hampir dua tahun. (Saya adalah pengembang yang lambat.) Terima kasih banyak!
Celarix
Ada beberapa masalah dengan jawaban saya. Ini berfungsi untuk sebagian besar situasi, tetapi perhatikan bahwa akan ada hasil yang berbeda tergantung pada apakah Anda memeriksa tabrakan X terlebih dahulu atau tabrakan Y terlebih dahulu. Juga perlu diingat bahwa penerowongan adalah masalah; ini akan gagal dengan objek berkecepatan tinggi karena mereka akan melewati ubin.
Lysol
Saya pikir saya pergi dengan X dulu sehingga lereng akan bekerja dengan baik. Bullet-through-paper tidak benar-benar masalah di platformer saya karena tidak ada yang bergerak cukup cepat untuk melewati ubin. Terima kasih atas masukan lebih lanjut!
Celarix
0

Anda terlalu memikirkan masalah dan menggabungkan beberapa masalah. Tapi tidak apa-apa karena, seperti yang Anda katakan, ini adalah masalah yang sangat terselesaikan dengan banyak jawaban hebat di luar sana.

Mari kita jabarkan:

  1. Tilemaps . Contoh pertama Anda adalah sprite yang berjalan melintasi sekelompok ubin yang diletakkan secara horizontal (atau meluncur ke bawah dinding ubin yang diletakkan secara vertikal, itu isomorfik). Salah satu solusi yang sangat elegan untuk ini adalah tidak memeriksa tepi ubin di mana kita tahu sprite tidak bisa, seperti tepi yang "bawah tanah" atau tepi yang membatasi ubin lain yang benar-benar padat.

    Anda benar bahwa sprite akan turun karena gravitasi, lalu bergerak ke samping, lalu tersangkut ... tetapi jawabannya adalah tidak peduli dengan tepi kiri atau kanan ubin yang berada di bawah tanah . Dengan begitu, rutin resolusi tabrakan Anda hanya menggerakkan sprite secara vertikal - dan sprite Anda dapat berjalan dengan cara yang menyenangkan.

    Lihatlah tutorial ubin Metanet untuk penjelasan langkah demi langkah tentang ini. Anda mengatakan dalam pertanyaan Anda bahwa Anda tidak menggunakan tilemap tradisional, tetapi tidak apa-apa juga: ubin statis ada di tilemap dan memperbarui seperti di atas, sambil memindahkan platform dan pembaruan seperti # 2 di bawah ini.

  2. AABB lainnya . Anda hanya akan mengalami masalah jika, dalam satu frame, sprite Anda dapat memindahkan jarak yang lebih besar dari lebar / tinggi sebagian besar AABB di game Anda. Jika tidak bisa, berarti Anda emas: selesaikan tabrakan satu-persatu dan itu akan bekerja dengan baik.

    Jika AABB dapat bergerak sangat cepat dalam satu bingkai maka Anda harus "menyapu" gerakan saat memeriksa tabrakan: potong gerakan menjadi fraksi yang lebih kecil dan periksa tabrakan pada setiap langkah.

drhayes
sumber