Advertisement
  1. Game Development
  2. Game Physics
Gamedevelopment

Asas 2D Fizik Pelantar, Bahagian 5: Objek vs. Pengesanan Pelanggaran Objek

by
Difficulty:BeginnerLength:LongLanguages:
This post is part of a series called Basic 2D Platformer Physics .
Basic 2D Platformer Physics, Part 4
Basic 2D Platformer Physics, Part 6: Object vs. Object Collision Response

Malay (Melayu) translation by Meyria (you can also view the original English article)

Dalam bahagian ini, kita akan mula berusaha ke arah menjadikan benda-benda untuk tidak hanya berinteraksi secara fizikal dengan tilemap sahaja, tetapi juga dengan objek lain, dengan melaksanakan mekanisme pengesanan perlanggaran antara objek permainan.

Demo

Demo menunjukkan hasil akhir tutorial ini. Gunakan WASD untuk menggerakkan charcter. Butang mouse tengah menanam platform satu hala, butang kanan tetikus melancarkan jubin pepejal, dan bar ruang spawns menimbulkan klon aksara. Slider menukar saiz watak pemain. Objek yang mengesan perlanggaran dibuat separa telus.

Demo telah diterbitkan di bawah Perpaduan 5.4.0f3, dan kod sumber juga serasi dengan versi Perpaduan ini.

Pengesanan Perlanggaran

Sebelum kita bercakap tentang apa-apa tindak balas perlanggaran, seperti menjadikannya mustahil bagi objek untuk saling melintasi antara satu sama lain, kita perlu terlebih dahulu mengetahui sama ada objek tersebut bertindih.

Ini mungkin operasi yang sangat mahal jika kita semata-mata memeriksa setiap objek terhadap setiap objek lain dalam permainan, bergantung pada berapa banyak objek aktif yang kini perlu ditangani. Jadi untuk meringankan pemproses miskin pemain kami sedikit, kami akan menggunakan ...

Pemisahan Spatial!

Pada dasarnya ini memisahkan ruang permainan menjadi kawasan yang lebih kecil, yang membolehkan kita menyemak perlanggaran antara objek milik hanya ke kawasan yang sama. Pengoptimuman ini sangat diperlukan dalam permainan seperti Terraria, di mana dunia dan bilangan objek bertabrakan yang mungkin besar dan objek jarang diletakkan. Dalam permainan skrin tunggal, di mana bilangan objek sangat dihalang oleh saiz skrin, ia sering tidak diperlukan, tetapi masih berguna.

Cara

Kaedah pemisahan ruang yang paling popular untuk ruang 2D ialah pokok quad; anda boleh menemui penerangannya dalam tutorial ini. Untuk permainan saya, saya menggunakan struktur rata, yang pada asasnya bermakna ruang permainan dibahagikan kepada segi empat tepat saiz tertentu, dan saya menyemak pelanggaran dengan objek yang berada di ruang segi empat yang sama.

The Rectangular space for our objects

Terdapat satu nuansa untuk ini: objek boleh tinggal di lebih daripada satu ruang kecil pada satu masa. Itu benar-benar halus - ia hanya bermakna bahawa kita perlu mengesan objek yang dimiliki oleh mana-mana partition objek bekas kami bertindih dengan.

An object residing in more than one sub-space

Data untuk Pemisahan

Pangkalan mudah. Kita perlu tahu berapa besar setiap sel dan array dua dimensi, di mana setiap elemen adalah senarai objek yang berada di kawasan tertentu. Kita perlu meletakkan data ini dalam kelas Peta.

Dalam kes kami, saya memutuskan untuk menyatakan saiz partition dalam jubin, dan oleh itu setiap partition adalah 16 by 16 jubin besar.

Untuk objek kami, kami akan mahu senarai kawasan yang objek tersebut kini bertindih, serta indeksnya dalam setiap partition. Mari tambahkan ini ke kelas MovingObject.

Daripada dua senarai, kita boleh menggunakan kamus tunggal, tetapi sayangnya overhed prestasi menggunakan bekas kompleks dalam lelaran semasa Perpaduan meninggalkan banyak yang dikehendaki, jadi kami akan tetap dengan senarai untuk demo.

Inisialisasi Partition

Mari kita teruskan untuk mengira berapa banyak sekatan yang kita perlukan untuk merangkumi keseluruhan kawasan peta. Andaian di sini adalah bahawa tiada objek boleh terapung di luar batas peta.

Sudah tentu, bergantung pada saiz peta, sekatan tidak sepadan dengan batas peta. Itulah sebabnya kami menggunakan siling nilai yang dikira untuk memastikan kami mempunyai sekurang-kurangnya cukup untuk merangkumi seluruh peta.

Mari kita buat partisyen sekarang.

Tiada apa yang berlaku di sini-kami hanya pastikan setiap sel mempunyai senarai objek yang sedia untuk kami beroperasi.

Menetapkan Partisyen Objek

Kini tiba masanya untuk membuat fungsi yang akan mengemas kini kawasan tumpang tindih objek tertentu.

Mula-mula, kita perlu tahu jubin peta mana objek itu bertindih dengan. Oleh kerana kita hanya menggunakan AABB, semua yang kita perlu periksa adalah apa jubin setiap sudut tanah AABB.

Sekarang untuk mendapatkan koordinat di ruang yang dibahagikan, semua yang perlu kita lakukan ialah membahagikan kedudukan jubin dengan saiz partition. Kita tidak perlu mengira partition sudut kanan bawah sekarang, kerana koordinat xnya akan sama dengan sudut kanan atas, dan koordinat y akan sama dengan bahagian kiri bawah.

Ini semua harus berfungsi berdasarkan andaian bahawa tiada objek akan dipindahkan di luar batas peta. Jika tidak, kita perlu mempunyai pemeriksaan tambahan di sini untuk mengabaikan objek yang berada di luar batas.

Sekarang, mungkin objek itu berada sepenuhnya dalam satu partition, ia boleh tinggal dalam dua, atau ia boleh menempati ruang di mana empat partition bertemu. Ini adalah di bawah andaian bahawa tiada objek lebih besar daripada saiz partition, di mana ia boleh menduduki keseluruhan peta dan semua sekatan jika ia cukup besar! Saya telah beroperasi di bawah andaian ini, jadi itulah bagaimana kita akan mengendalikan ini dalam tutorial. Pengubahsuaian untuk membolehkan objek yang lebih besar agak remeh, jadi saya akan menerangkannya juga.

Mari kita mulakan dengan memeriksa kawasan yang bertindih dengan watak. Jika semua koordinat partisi sudut sama, maka objek itu hanya menyisakan satu kawasan.

The object occupying a single area

Jika itu bukan kes dan koordinat adalah sama pada paksi-x, maka objek itu bertindih dengan dua petak yang berbeza secara menegak.

An object occupying two of the same partitions along the x-axis

Jika kami menyokong objek yang lebih besar daripada sekatan, itu akan menjadi cukup jika kami hanya menambah semua partition dari sudut kiri atas ke kiri bawah satu menggunakan gelung.

Logik yang sama berlaku jika hanya koordinat menegak yang sama.

An object occupying two of the same partitions along the y-axis

Akhirnya, jika semua koordinat berbeza, kita perlu menambah semua empat kawasan.

An object occupying four quadrants

Sebelum kita beralih dengan fungsi ini, kita perlu dapat menambah dan mengeluarkan objek dari partition tertentu. Mari buat fungsi ini, bermula dengan penambahan.

Seperti yang anda lihat, prosedurnya sangat mudah-kami menambah indeks kawasan tersebut ke senarai kawasan yang bertindih, kami menambah indeks yang sesuai dengan senarai id ids, dan akhirnya menambah objek ke partition tersebut.

Sekarang mari kita buat fungsi penyingkiran.

Seperti yang anda dapat lihat, kami akan menggunakan koordinat kawasan bahawa watak itu tidak lagi bertindih dengan, indeksnya dalam senarai objek dalam kawasan itu, dan rujukan kepada objek yang perlu kita keluarkan.

Untuk mengeluarkan objek, kami akan menukarnya dengan objek terakhir dalam senarai. Ini akan menghendaki kami juga memastikan bahawa indeks objek untuk kawasan tertentu ini dikemas kini dengan objek yang telah kami bawa. Jika kita tidak menukar objek itu, kita perlu mengemas kini indeks semua objek yang pergi selepas yang kita perlu alihkan. Sebaliknya, kita perlu mengemas kini hanya yang kita bertukar.

Mempunyai kamus di sini akan menjimatkan banyak masalah, tetapi mengeluarkan objek dari kawasan adalah operasi yang diperlukan jauh lebih jarang daripada melewati kamus, yang perlu dilakukan setiap bingkai untuk setiap objek apabila kita sedang mengemas kini tumpang tindih objek kawasan-kawasan.

Sekarang kita perlu mencari kawasan yang kita bimbangkan dalam senarai kawasan objek yang ditukar, dan menukar indeks dalam senarai id ke indeks objek yang dibuang.

Akhirnya, kita boleh mengeluarkan objek terakhir dari partition, yang kini merupakan rujukan kepada objek yang diperlukan untuk dibuang.

Fungsi keseluruhan sepatutnya seperti ini:

Mari kita beralih ke fungsi UpdateAreas.

Kami tahu kawasan mana watak itu bertindih kerangka ini, tetapi bingkai terakhir objek itu sudah boleh ditugaskan ke kawasan yang sama atau berbeza. Pertama, mari gelung melalui kawasan-kawasan lama, dan jika objek tidak lagi bertindih dengan mereka maka mari kita keluarkan objek dari ini.

Sekarang mari kita gelung melalui kawasan baru, dan jika objek belum ditugaskan sebelumnya, mari tambahkan sekarang.

Akhir sekali, kosongkan senarai kawasan bertindih supaya ia bersedia memproses objek seterusnya.

Itu sahaja! Fungsi akhir sepatutnya seperti ini:

Mengesan Perlanggaran Antara Objek

Pertama sekali, kita perlu memastikan untuk memanggil UpdateAreas pada semua objek permainan. Kita boleh melakukannya dalam gelung kemas kini utama, selepas setiap panggilan kemas kini objek individu.

Sebelum kita membuat fungsi di mana kita menyemak semua perlanggaran, mari kita buat struct yang akan memegang data perlanggaran.

Ini akan menjadi sangat berguna, kerana kita akan dapat mengekalkan data seperti pada saat perlanggaran, sedangkan jika kita menyimpan hanya rujukan kepada objek yang kita bertabrakan, kita tidak akan terlalu sedikit untuk bekerja dengan, tetapi juga kedudukan dan pembolehubah lain boleh diubah untuk objek tersebut sebelum masa sebenar kita dapat memproses perlanggaran dalam gelaran kemas kinian objek.

Data yang kami simpan adalah rujukan kepada objek yang kami bertembung dengan, tumpang tindih, kelajuan kedua-dua objek pada masa perlanggaran, kedudukan mereka, dan juga kedudukan mereka sebelum masa perlanggaran.

Mari pindah ke kelas MovingObject dan buat satu bekas untuk data perlanggaran yang baru dibuat yang perlu kita hadapi.

Sekarang mari kita kembali ke kelas Peta dan buat fungsi CheckCollisions. Ini akan menjadi tugas berat kami di mana kita mengesan perlanggaran di antara semua objek permainan.

Untuk mengesan perlanggaran, kami akan melelong melalui semua sekatan.

Untuk setiap partition, kami akan melelong melalui setiap objek di dalamnya.

Untuk setiap objek, kita periksa setiap objek lain yang lebih jauh ke bawah senarai dalam partition. Dengan cara ini kita akan menyemak setiap perlanggaran hanya satu kali.

Sekarang kita dapat memeriksa sama ada AABBs objek tersebut bertindih antara satu sama lain.

Inilah yang berlaku dalam fungsi OverlapsSigned AABB.

Seperti yang anda lihat, jika saiz AABB pada mana-mana paksi adalah sifar, ia tidak boleh bertembung. Perkara lain yang dapat anda perhatikan adalah bahawa jika pertindihan sama dengan sifar, fungsi itu akan kembali benar, kerana ia akan menolak kes-kes di mana jurang antara AABBs lebih besar daripada sifar. Itulah sebabnya jika jika objek menyentuh antara satu sama lain dan tidak bertindih, kami masih ingin mendapatkan maklumat bahawa ini adalah kesnya, jadi kami memerlukannya untuk diteruskan.

Sebagai perkara terakhir, sebaik sahaja perlanggaran dikesan, kami mengira berapa banyak AABB bertindih dengan AABB yang lain. Tali bertindan ditandatangani, jadi dalam kes ini jika AABB bertindih di bahagian kanan AABB ini, tumpang tindih pada paksi x akan negatif, dan jika AABB yang lain berada di sisi kiri AABB ini, tumpang tindih pada paksi x akan positif. Ini akan memudahkan kemudian untuk keluar dari kedudukan bertindih, seperti yang kita tahu di mana arah kita mahu objek itu bergerak.

Bergerak kembali ke fungsi CheckCollisions kami, jika tidak ada pertindihan, itu saja, kita boleh berpindah ke objek seterusnya, tetapi jika terjadi tumpang tindih maka kita perlu menambahkan data tabrakan ke kedua objek.

Untuk membuat perkara mudah bagi kami, kami akan mengandaikan bahawa 1 (speed1, pos1, oldPos1) 1 dalam struktur CollisionData selalu merujuk kepada pemilik data perlanggaran, dan 2 adalah data mengenai objek lain.

Perkara lain ialah, pertindihan dikira dari perspektif obj1. Bertindih obj2 perlu ditiadakan, jadi jika obj1 perlu bergerak ke kiri untuk keluar dari perlanggaran, obj2 perlu bergerak ke kanan untuk keluar dari tabrakan yang sama.

Masih ada satu perkara yang kecil untuk dijaga-kerana kita melewatinya melalui partition peta dan satu objek boleh berada dalam pelbagai partition pada sama, sehingga empat dalam kes kita, mungkin kita akan mengesan tumpang tindih untuk sama dua objek sehingga empat kali.

Untuk mengalih keluar kemungkinan ini, kami sememangnya memeriksa sama ada kami telah mengesan perlanggaran antara dua objek. Sekiranya itu berlaku, kami melangkau lelaran.

Fungsi HasCollisionDataFor dilaksanakan seperti berikut.

Ia hanya melelepkan melalui semua struktur data perlanggaran dan melihat sama ada mana-mana sudah dimiliki oleh objek yang akan kita lihat untuk perlanggaran.

Ini harus baik dalam kes penggunaan umum kerana kita tidak mengharapkan objek untuk bertabrakan dengan banyak objek lain, jadi melihat melalui senarai akan cepat. Walau bagaimanapun, dalam senario yang berbeza mungkin lebih baik untuk menggantikan senarai CollisionData dengan kamus, jadi bukannya berulang kita dapat memberitahu segera jika elemen sudah ada atau tidak.

Perkara lain ialah, semakan ini menjimatkan kami daripada menambah banyak salinan pelanggaran yang sama ke dalam senarai yang sama, tetapi jika objek tidak bertembung, kami juga akan memeriksa bertindih beberapa kali jika kedua-dua objek itu berada pada partisyen yang sama.

Ini tidak boleh menjadi kebimbangan besar, kerana pemeriksaan perlanggaran adalah murah dan keadaan tidak begitu biasa, tetapi jika masalah itu, penyelesaiannya mungkin hanya mempunyai matriks pelanggaran yang diperiksa atau kamus dua hala, isi itu kerana perlanggaran telah diperiksa, dan menetapkannya semula sebelum kita memanggil fungsi CheckCollisions.

Sekarang mari kita panggil fungsi yang baru sahaja selesai di gelung permainan utama.

Itu sahaja! Sekarang semua objek kami harus mempunyai data mengenai perlanggaran.

Untuk menguji jika semuanya berjalan dengan baik, jom kita buat supaya jika watak bertembung dengan objek, sprit watak akan bertukar separa telus.

Reviewing Collisions via Animation

Seperti yang anda dapat lihat, pengesanan seolah-olah berfungsi dengan baik!

Ringkasan

Itu sahaja untuk bahagian lain dari siri fizik 2D platformer yang mudah. Kami berjaya melaksanakan mekanisme pemisahan spatial yang sangat mudah dan mengesan perlanggaran di antara setiap objek.

Sekiranya anda mempunyai soalan, tip bagaimana untuk melakukan sesuatu yang lebih baik, atau hanya mempunyai pendapat mengenai tutorial, jangan ragu untuk menggunakan bahagian komen untuk memberitahu saya!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.