Menerapkan kawat pembungkus (seperti Worms Ninja Rope) dalam mesin fisika 2D

34

Saya telah mencoba beberapa fisika tali baru-baru ini, dan saya telah menemukan bahwa solusi "standar" - membuat tali dari serangkaian benda yang diikat bersama dengan pegas atau sambungan - tidak memuaskan. Terutama ketika tali ayun relevan dengan gameplay. Saya tidak terlalu peduli tentang kemampuan tali untuk membungkus atau melorot (ini bisa dipalsukan untuk visual).

Untuk gameplay, yang penting adalah kemampuan tali untuk membungkus lingkungan dan kemudian membuka bungkusnya. Bahkan tidak harus berperilaku seperti tali - sebuah "kawat" yang terdiri dari segmen garis lurus bisa digunakan. Inilah ilustrasi:

Tali ninja, melingkari rintangan

Ini sangat mirip dengan "Ninja Rope" dari game Worms.

Karena saya menggunakan mesin fisika 2D - lingkungan saya terdiri dari poligon cembung 2D. (Khususnya saya menggunakan SAT di Farseer.)

Jadi pertanyaan saya adalah ini: Bagaimana Anda menerapkan efek "pembungkus"?

Tampaknya cukup jelas bahwa kawat akan terdiri dari serangkaian segmen garis yang "terpecah" dan "bergabung". Dan segmen terakhir (aktif) dari garis itu, di mana objek bergerak menempel, akan menjadi sambungan dengan panjang tetap.

Tapi apa matematika / algoritma yang terlibat untuk menentukan kapan dan di mana segmen garis aktif perlu dibagi? Dan kapan harus bergabung dengan segmen sebelumnya?

(Sebelumnya pertanyaan ini juga bertanya tentang melakukan ini untuk lingkungan yang dinamis - Saya telah memutuskan untuk memecahnya menjadi pertanyaan lain.)

Andrew Russell
sumber

Jawaban:

18

Untuk menentukan kapan harus membagi tali, Anda harus melihat area yang tali itu tutupi setiap bingkai. Apa yang Anda lakukan adalah Anda melakukan tabrakan dengan area yang tertutup dan geometri level Anda. Area yang dicakup oleh ayunan harus berupa busur. Jika ada tabrakan, Anda perlu membuat segmen baru ke tali. Periksa sudut yang bertabrakan dengan busur ayun. Jika ada beberapa sudut yang bertabrakan dengan busur ayun, Anda harus memilih satu di mana sudut antara tali selama bingkai sebelumnya dan titik tumbukan adalah yang terkecil.

Diagram membantu situasi tali ninja

Cara Anda melakukan deteksi tabrakan adalah untuk akar segmen tali saat ini, O, posisi ujung tali pada bingkai sebelumnya, A, posisi ujung tali pada bingkai saat ini, B, dan setiap titik sudut P dalam poligonal tingkat geometri, Anda menghitung (OA x OP), (OP x OB) dan (OA x OB), di mana "x" mewakili mengambil koordinat Z dari produk silang antara dua vektor. Jika ketiga hasil memiliki tanda yang sama, negatif atau positif, dan panjang OP lebih kecil dari panjang segmen tali, titik P berada di dalam area yang dicakup oleh ayunan, dan Anda harus membelah tali. Jika Anda memiliki beberapa titik sudut bertabrakan, Anda akan ingin menggunakan yang pertama yang mengenai tali, artinya titik di mana sudut antara OA dan OP adalah yang terkecil. Gunakan dot produk untuk menentukan sudutnya.

Sedangkan untuk bergabung dengan segmen, lakukan perbandingan antara segmen sebelumnya dan busur segmen Anda saat ini. Jika segmen saat ini berayun dari sisi kiri ke sisi kanan atau sebaliknya, Anda harus bergabung dengan segmen tersebut.

Untuk matematika untuk bergabung dengan segmen kami akan menggunakan titik lampiran dari segmen tali sebelumnya, Q, serta yang kami miliki untuk kasus pemisahan. Jadi sekarang, Anda ingin membandingkan vektor QO, OA dan OB. Jika tanda (QO x OA) berbeda dari tanda (QO x OB), tali telah berpindah dari kiri ke kanan atau sebaliknya, dan Anda harus bergabung dengan segmen. Ini tentu saja juga bisa terjadi jika tali berayun 180 derajat, jadi jika Anda ingin tali dapat membungkus satu titik di ruang alih-alih bentuk poligon, Anda mungkin ingin menambahkan kasing khusus untuk itu.

Metode ini tentu saja mengasumsikan bahwa Anda melakukan deteksi tabrakan untuk objek yang tergantung pada tali, sehingga tidak berakhir di dalam geometri level.

Pekuja
sumber
1
Masalah dengan pendekatan ini adalah bahwa kesalahan presisi floating-point memungkinkan tali untuk melewati titik.
Andrew Russell
16

Sudah lama sejak saya bermain Worms, tetapi dari apa yang saya ingat - ketika tali membungkus sesuatu, hanya ada satu bagian (lurus) dari tali yang bergerak pada satu waktu. Sisa tali menjadi statis

Jadi sangat sedikit fisika aktual yang terlibat. Bagian aktif dapat dimodelkan sebagai pegas kaku tunggal dengan massa di ujungnya

Bit yang menarik adalah logika untuk memisahkan / menyambung bagian tali yang tidak aktif ke / dari bagian aktif.

Saya membayangkan akan ada 2 operasi utama:

'Split' - Tali telah memotong sesuatu. Membaginya di persimpangan menjadi bagian tidak aktif dan bagian baru, lebih pendek, aktif

'Bergabung' - Tali aktif telah pindah ke posisi di mana persimpangan terdekat tidak ada lagi (ini mungkin hanya tes produk sudut / titik sederhana?). Bergabung kembali 2 bagian, membuat bagian baru, lebih lama, aktif

Dalam adegan yang dibangun dari poligon 2D, semua titik perpecahan harus berada pada titik pada jala tabrakan. Deteksi tabrakan dapat disederhanakan menjadi sesuatu di sepanjang garis 'Jika tali melewati titik pada pembaruan ini, terbelah / bergabung dengan tali di titik itu?

bluescrn
sumber
2
Orang ini tepat di tempat ... Sebenarnya, itu bukan musim semi "kaku", Anda hanya memutar beberapa garis lurus di sekitar ...
speeder
Jawaban Anda secara teknis benar. Tapi saya agak berasumsi bahwa memiliki segmen garis dan membelah dan bergabung dengan mereka sudah jelas. Saya tertarik pada algoritma / matematika yang sebenarnya untuk melakukan itu. Saya telah membuat pertanyaan saya lebih spesifik.
Andrew Russell
3

Lihatlah bagaimana tali ninja di Gusanos diimplementasikan:

  • Tali itu bertindak seperti partikel sampai melekat pada sesuatu.
  • Setelah terpasang, tali hanya memberikan kekuatan ke cacing.
  • Melampirkan ke objek dinamis (seperti cacing lainnya) masih merupakan TODO: dalam kode ini.
  • Saya tidak dapat mengingat jika membungkus benda / sudut didukung ...

Kutipan yang relevan dari ninjarope.cpp :


void NinjaRope::think()
{
    if ( m_length > game.options.ninja_rope_maxLength )
        m_length = game.options.ninja_rope_maxLength;

    if (!active)
        return;

    if ( justCreated && m_type->creation )
    {
        m_type->creation->run(this);
        justCreated = false;
    }

    for ( int i = 0; !deleteMe && i < m_type->repeat; ++i)
    {
        pos += spd;

        BaseVec<long> ipos(pos);

        // TODO: Try to attach to worms/objects

        Vec diff(m_worm->pos, pos);
        float curLen = diff.length();
        Vec force(diff * game.options.ninja_rope_pullForce);

        if(!game.level.getMaterial( ipos.x, ipos.y ).particle_pass)
        {
            if(!attached)
            {
                m_length = 450.f / 16.f - 1.0f;
                attached = true;
                spd.zero();
                if ( m_type->groundCollision  )
                    m_type->groundCollision->run(this);
            }
        }
        else
            attached = false;

        if(attached)
        {
            if(curLen > m_length)
            {
                m_worm->addSpeed(force / curLen);
            }
        }
        else
        {
            spd.y += m_type->gravity;

            if(curLen > m_length)
            {
                spd -= force / curLen;
            }
        }
    }
}
Leftium
sumber
1
Uhmn ... ini sepertinya tidak menjawab pertanyaan saya sama sekali. Inti dari pertanyaan saya adalah melilitkan tali mengelilingi dunia yang terbuat dari poligon. Gusanos tampaknya tidak memiliki dunia pembungkus dan bitmap.
Andrew Russell
1

Saya khawatir saya tidak bisa memberi Anda algoritma konkret dari atas kepala saya, tetapi terpikir oleh saya bahwa hanya ada dua hal yang penting untuk mendeteksi tabrakan untuk tali ninja: setiap dan semua berpotensi bertabrakan simpul pada hambatan dalam radius "split" terakhir yang sama dengan panjang segmen yang tersisa; dan arah ayunan saat ini (searah atau berlawanan arah jarum jam). Jika Anda membuat daftar sementara sudut dari "split" vertex ke masing-masing simpul terdekat, algoritma Anda hanya perlu peduli jika segmen Anda akan berayun melewati sudut itu untuk setiap titik yang diberikan. Jika ya, maka Anda perlu melakukan operasi split, yang mudah seperti pie - Ini hanya garis dari vertex split terakhir ke split baru, dan kemudian sisa baru dihitung.

Saya pikir hanya masalah simpul. Jika Anda dalam bahaya menabrak segmen antara simpul pada rintangan, maka deteksi tabrakan normal Anda untuk orang yang tergantung di ujung tali harus masuk. Dengan kata lain, tali Anda hanya akan "tersangkut" pada sudutnya, jadi segmen antara tidak akan masalah.

Maaf saya tidak punya sesuatu yang konkret, tapi mudah-mudahan itu membuat Anda di tempat yang Anda butuhkan, secara konseptual, untuk mewujudkan hal ini. :)

Pi-3
sumber
1

Berikut adalah pos yang memiliki tautan ke makalah tentang jenis simulasi serupa (dalam konteks teknik / akademik alih-alih untuk game): https://gamedev.stackexchange.com/a/10350/6398

Saya telah mencoba setidaknya dua pendekatan berbeda untuk deteksi tumbukan + respons untuk simulasi "kawat" semacam ini (seperti yang terlihat dalam game Umihara Kawase); setidaknya, saya pikir inilah yang Anda cari - sepertinya tidak ada istilah khusus untuk simulasi semacam ini, saya hanya cenderung menyebutnya "kawat" daripada "tali" karena sepertinya kebanyakan orang anggap "tali" identik dengan "rantai partikel". Dan, jika Anda ingin perilaku tongkat-ish dari tali ninja (yaitu dapat mendorong DAN menarik), ini lebih seperti kawat kaku daripada tali. Bagaimanapun..

Jawaban Pekuja baik, Anda dapat menerapkan deteksi tabrakan berkelanjutan dengan memecahkan waktu ketika area yang ditandatangani dari tiga poin adalah 0.

(Saya tidak dapat sepenuhnya mengingat OTOH tetapi Anda dapat mendekatinya sebagai berikut: temukan waktu t ketika titik a terkandung dalam garis yang melewati b, c, (saya pikir saya melakukan ini dengan menyelesaikan ketika titik (ab, cb) = 0 untuk menemukan nilai t), dan kemudian diberi waktu yang valid 0 <= t <1, cari posisi parametrik s pada segmen bc, yaitu a = (1-s) b + s c dan jika a berada di antara b dan c (yaitu jika 0 <= s <= 1) itu adalah tabrakan yang valid.

AFAICR Anda juga dapat mendekatinya (mis. Selesaikan untuk s dan kemudian tancapkan ini untuk menemukan t) tetapi itu jauh kurang intuitif. (Maaf jika ini tidak masuk akal, saya tidak punya waktu untuk menggali catatan saya dan sudah beberapa tahun!))

Jadi, Anda sekarang dapat menghitung semua waktu di mana peristiwa terjadi (yaitu simpul tali harus dimasukkan atau dihapus); proses peristiwa paling awal (masukkan atau hapus simpul) dan kemudian ulangi / kambuh sampai tidak ada lagi peristiwa antara t = 0 dan t = 1.

Satu peringatan tentang pendekatan ini: jika benda yang dililitkan tali itu dinamis (terutama jika Anda mensimulasikannya DAN pengaruhnya pada tali, dan sebaliknya) maka akan ada masalah jika benda-benda tersebut menjepit / melewati masing-masing lainnya - kawat bisa kusut. Dan itu pasti akan menjadi tantangan untuk mencegah interaksi / gerakan semacam ini (sudut-sudut objek saling menyelinap) dalam simulasi fisika gaya box2d .. sejumlah kecil penetrasi antara objek adalah perilaku normal dalam konteks itu.

(Setidaknya .. ini adalah masalah dengan salah satu implementasi "kawat" saya.)

Solusi yang berbeda, yang jauh lebih stabil tetapi melewatkan beberapa tabrakan dalam kondisi tertentu adalah dengan hanya menggunakan tes statis (yaitu jangan khawatir tentang pemesanan berdasarkan waktu, hanya membagi secara membagi setiap segmen dalam tabrakan saat Anda menemukannya), yang dapat berupa jauh lebih kuat - kawat tidak akan kusut di sudut dan sedikit penetrasi akan baik-baik saja.

Saya pikir pendekatan Pekuja bekerja untuk ini juga, namun ada pendekatan alternatif. Salah satu pendekatan yang saya gunakan adalah menambahkan data tumbukan bantu: pada setiap titik cembung v di dunia (yaitu sudut-sudut bentuk yang dapat dililit tali), tambahkan titik u membentuk segmen garis diarahkan uv, di mana u adalah beberapa titik "di dalam sudut" (yaitu di dalam dunia, "di belakang" v; untuk menghitung Anda dapat melemparkan sinar ke dalam dari v sepanjang yang diinterpolasi normal dan berhenti agak jauh setelah v atau sebelum sinar berpotongan dengan tepi dunia dan keluar dari wilayah padat. Atau, Anda bisa secara manual mengecat segmen ke dunia menggunakan alat visual / editor level).

Lagi pula, Anda sekarang memiliki satu set "corner linesegs" uv; untuk setiap uv, dan setiap segmen ab dalam kawat, periksa apakah ab dan uv berpotongan (yaitu query persimpangan interseg-lineseg garis statis boolean); jika demikian, ulangi (pisahkan garis-garis ab ke dalam av dan vb, yaitu masukkan v), catat ke arah mana tali ditekuk pada v. Kemudian untuk setiap pasangan garis-garis tetangga ab, bc dalam kawat, uji apakah arah tikungan arus pada sama dengan ketika b dihasilkan (semua tes "arah belokan" ini hanya uji area yang ditandatangani); jika tidak, gabungkan kedua segmen menjadi ac (mis. hapus b).

Atau mungkin saya bergabung dan kemudian berpisah, saya lupa - tetapi itu pasti bekerja di setidaknya satu dari dua kemungkinan pesanan! :)

Mengingat semua segmen kawat yang dihitung untuk kerangka saat ini, Anda kemudian dapat mensimulasikan batasan jarak antara dua titik akhir kawat (dan Anda bahkan dapat melibatkan titik-titik interior, yaitu titik kontak antara kawat dan dunia, tetapi itu sedikit lebih terlibat) ).

Ngomong-ngomong, semoga ini akan bermanfaat ... makalah di posting yang saya tautkan juga harus memberi Anda beberapa ide.

raigan
sumber
0

Salah satu pendekatan untuk ini adalah memodelkan tali sebagai partikel yang dapat di collidable, dihubungkan oleh pegas. (Yang cukup kaku, bahkan mungkin hanya sebagai tulang saja). Partikel-partikel bertabrakan dengan lingkungan, memastikan tali membungkus barang-barang.

Berikut ini adalah demo dengan sumber: http://www.ewjordan.com/rgbDemo/

(Pindah ke kanan di tingkat pertama, ada tali merah yang dapat berinteraksi dengan Anda)

Rachel Blum
sumber
2
Eh - ini khusus yang tidak saya inginkan (lihat pertanyaannya).
Andrew Russell
Ah. Itu tidak jelas dari pertanyaan awal. Terima kasih telah meluangkan waktu untuk mengklarifikasi begitu banyak. (Diagram hebat!) Saya masih akan pergi dengan serangkaian sambungan tetap yang sangat kecil, yang bertentangan dengan melakukan pemisahan dinamis - kecuali jika itu masalah kinerja besar di lingkungan Anda, itu lebih mudah untuk dikodekan.
Rachel Blum