Bagaimana cara mencegah karakter platformer saya terpotong di ubin dinding?

9

Saat ini, saya memiliki platformer dengan ubin untuk medan (gambar dipinjam dari Cave Story). Game ini ditulis dari awal menggunakan XNA, jadi saya tidak menggunakan mesin atau mesin fisika yang ada.

Tabrakan ubin dijelaskan persis seperti yang dijelaskan dalam jawaban ini (dengan SAT sederhana untuk persegi panjang dan lingkaran), dan semuanya berfungsi dengan baik.

Kecuali ketika pemain berlari ke dinding saat jatuh / melompat. Dalam hal ini, mereka akan menangkap ubin dan mulai berpikir mereka telah menyentuh lantai atau langit-langit yang sebenarnya tidak ada.

Gambar penangkapan karakter

Dalam tangkapan layar ini, pemain bergerak ke kanan dan jatuh ke bawah. Jadi setelah gerakan, tabrakan diperiksa - dan pertama, ternyata karakter pemain bertabrakan dengan ubin ke-3 dari lantai, dan didorong ke atas. Kedua, dia ditemukan bertabrakan dengan ubin di sampingnya, dan mendorong ke samping - hasil akhirnya adalah karakter pemain berpikir dia ada di tanah dan tidak jatuh, dan 'menangkap' di ubin selama dia berlari ke dalamnya .

Saya bisa menyelesaikan ini dengan mendefinisikan ubin dari atas ke bawah sebagai gantinya, yang membuatnya jatuh dengan lancar, tetapi kemudian kasus terbalik terjadi dan dia akan mengenai langit-langit yang tidak ada di sana ketika melompat ke atas ke dinding.

Bagaimana saya harus mendekati menyelesaikan ini, sehingga karakter pemain bisa saja jatuh di dinding seperti yang seharusnya?

doppelgreener
sumber
Mirip dengan pertanyaan ini? gamedev.stackexchange.com/questions/14486/…
MichaelHouse
@ Byte56 Pertanyaannya tidak sama, tetapi jawabannya mungkin bisa membantu.
doppelgreener
Catatan: Saya punya sedikit waktu dalam beberapa minggu terakhir untuk bereksperimen dengan jawaban di sini. Saya telah mengimplementasikan resolusi tabrakan dunia seperti yang dijawab dalam pertanyaan @ Byte56 yang ditautkan, yang memiliki bug terpisah pada kecepatan tinggi, dan belum dapat mencoba jawaban untuk pertanyaan ini. Saya akan mencobanya ketika saya bisa dan baik menerima jawaban ketika saya bisa, atau memposting saya sendiri jika saya menyelesaikannya sendiri.
doppelgreener

Jawaban:

8

Pendekatan yang paling sederhana dan lebih tahan-gagal adalah tidak memeriksa tabrakan pada sisi tersembunyi. Jika Anda memiliki dua ubin dinding, satu tepat di atas yang lain, maka tepi bawah ubin atas dan tepi atas ubin bawah tidak harus diperiksa untuk bertabrakan dengan pemain.

Anda dapat menentukan tepi mana yang valid selama melewati sederhana peta ubin, menyimpan tepi luar sebagai tanda pada setiap lokasi ubin. Anda juga bisa melakukan ini saat runtime dengan memeriksa ubin yang berdekatan selama deteksi tabrakan.

Ada versi yang lebih maju dari teknik yang sama ini yang membuatnya lebih mudah dan lebih cepat untuk mendukung ubin non-persegi juga.

Saya sarankan Anda membaca artikel di bawah ini. Mereka adalah perkenalan sederhana yang layak untuk melakukan fisika dasar dan deteksi tabrakan di platformer modern (seperti Cave Story). Jika Anda ingin merasakan Mario yang lebih tua, ada beberapa trik yang perlu dikhawatirkan, tetapi sebagian besar melibatkan penanganan melompat dan animasi daripada tabrakan.

http://www.metanetsoftware.com/technique/tutorialA.html http://www.metanetsoftware.com/technique/tutorialB.html

Sean Middleditch
sumber
Bisakah Anda mengklarifikasi cara mengabaikan beberapa tepi selama tabrakan? Saya biasanya melihat tabrakan terdeteksi sebagai persimpangan dua persegi panjang (pemain batas dan batas ubin). Ketika Anda mengatakan untuk tidak memeriksa tabrakan dengan tepi individu, apakah itu berarti bahwa algoritma tabrakan bukan persimpangan persegi panjang-persegi panjang tetapi sesuatu yang lain? Deskripsi Anda masuk akal, tapi saya tidak yakin seperti apa implementasinya nantinya.
David Gouveia
Ya, lakukan saja tabrakan garis persegi panjang. Hanya disederhanakan karena garis selalu sejajar sumbu. Anda bisa menguraikan kotak-kotak Anda.
Sean Middleditch
5

Di sini pesanan saya akan melakukan hal-hal ....

1) Simpan X saat ini, karakter Y

2) Pindahkan arah X

3) Periksa semua sudut karakter dengan mendapatkan data ubin dan periksa apakah itu solid dengan melakukan hal berikut: (X dan Y adalah posisi karakter)

  • untuk kiri atas: lantai (X / tileWidth), lantai (Y / tileHeight);
  • untuk kanan atas: lantai ((X + characterWidth) / tileWidth), lantai (Y / tileHeight);
  • untuk kiri bawah: lantai (X + / tileWidth), lantai ((Y + characterHeight) / tileHeight);
  • untuk kanan bawah: lantai ((X + characterWidth) / tileWidth), lantai ((Y + characterHeight) / tileHeight);

... untuk mendapatkan data ubin yang benar dari data peta

4) Jika ada ubin yang solid, maka Anda perlu memaksa X ke posisi terbaik dengan mengembalikan X yang disimpan dan ...

  • jika Anda bergerak ke kiri: X = lantai (X / tileWidth) * tileWidth;
  • jika Anda bergerak ke kanan: X = ((lantai ((X + characterWidth) / tileWidth) + 1) * tileWidth) - characterWidth;

5) Ulangi 2-4 menggunakan Y

Jika karakter Anda lebih tinggi dari ubin, Anda perlu memeriksa ubin lainnya. Untuk melakukan ini, Anda perlu mengulang dan menambahkan tileHeight ke posisi karakterY untuk mendapatkan ubin

int characterBlockHeight = 3;

// check all tiles and intermediate tiles down the character body
for (int y = 0; y < characterBlockHeight - 1; y++) {
    tile = getTile(floor(characterX / tileWidth), floor((characterY + (y * tileHeight)) / tileHeight));
    ... check tile OK....
}

// finally check bottom
tile = getTile(floor(characterX / tileWidth), floor((characterY + characterHeight) / tileHeight);
... check tile OK....

Jika karakter lebih lebar dari 1 blok maka lakukan hal yang sama tetapi ganti characterY, characterHeight, tileHeight, dll dengan characterX, characterWidth, dll

John
sumber
2

Bagaimana jika Anda memeriksa kemungkinan tabrakan sebagai bagian dari metode pergerakan pemain, dan gerakan ditolak yang menyebabkan pemain meluncur ke objek lain? Ini akan mencegah pemain untuk mendapatkan 'di dalam' blok, dan karena itu dia tidak bisa 'di atas' dari blok di bawahnya.

Beberapa pria
sumber
1

Saya mengalami masalah yang hampir sama persis dalam permainan yang saya kerjakan saat ini. Cara saya menyelesaikannya adalah dengan menyimpan area bagian yang tumpang tindih saat menguji tabrakan, dan kemudian menangani tabrakan tersebut berdasarkan prioritas mereka (area terbesar terlebih dahulu), kemudian memeriksa ulang setiap tabrakan untuk melihat apakah telah diselesaikan oleh yang sebelumnya. penanganan.

Dalam contoh Anda, area tumbukan sumbu x akan lebih besar dari sumbu y, jadi itu akan ditangani terlebih dahulu. Kemudian sebelum mencoba menangani tabrakan sumbu-y, ia akan memeriksa dan memastikan bahwa itu tidak lagi bertabrakan setelah dipindahkan pada sumbu-x. :)

Nick Badal
sumber
1

Perbaikan yang sederhana, tetapi tidak sempurna, adalah mengubah bentuk kotak tabrakan pemain sehingga bukan kotak. Potong sudut untuk membuatnya seperti segi delapan atau yang serupa. Dengan cara ini, ketika dia bertabrakan dengan ubin seperti yang ada di dinding, dia akan meluncur turun dan tidak tertangkap. Ini tidak sempurna karena Anda masih bisa melihat dia menangkap sudut sedikit, tetapi dia tidak akan macet dan sangat mudah diterapkan.

Amplify91
sumber
1

Masalah yang sangat mirip tercakup dalam tutorial ini: Pengantar Pengembangan Game . Bagian yang relevan dari video adalah pada 1:44 , menjelaskan dengan diagram dan potongan kode.

Perhatikan 14-tilemap.py menunjukkan masalah kliping, tetapi diperbaiki di 15-blocker-sides.py

Saya tidak bisa menjelaskan mengapa contoh tutorial terakhir tidak terpotong ketika kode Anda melakukannya, tetapi saya pikir ini ada hubungannya dengan:

  • Respons tabrakan bersyarat berdasarkan jenis ubin (tepi mana yang sebenarnya aktif.)
  • Pemain selalu 'jatuh.' Meskipun pemain tampaknya beristirahat di ubin, pemain sebenarnya berulang kali jatuh melalui ubin, kemudian didorong kembali ke atas. ( self.restingAnggota dalam kode hanya digunakan untuk memeriksa apakah pemain bisa melompat. Meskipun demikian, saya tidak bisa membuat pemain melakukan lompatan 'ganda' dari dinding. Namun secara teori, itu mungkin saja dilakukan)
Leftium
sumber
0

Metode lain (yang saya jawab dengan pertanyaan yang terkait dengan Byte56) adalah untuk memeriksa apakah resolusi tabrakan menempatkan karakter di tempat kosong atau tidak. Jadi dalam masalah Anda, Anda mendapatkan tabrakan dari langit-langit persegi panjang dalam untuk memindahkannya, yang akan ilegal (karena Anda masih bertabrakan dengan ubin lain). Alih-alih, Anda hanya memindahkannya jika dipindahkan ke ruang kosong (seperti bagaimana tabrakan dari ubin atas akan memindahkan Anda ke kiri), dan setelah Anda menemukan tabrakan itu, Anda selesai.

Jawaban yang saya berikan memiliki kode, tetapi menjadi terlalu rumit. Saya akan melacak semua tabrakan dalam jangka waktu itu dan hanya mengambil satu yang mengarah ke ruang kosong. Namun jika tidak ada, saya pikir saya terpaksa mengatur ulang posisi karakter ke posisi terakhir, namun itu benar-benar jelek dan mungkin Anda lebih suka mencoba menerapkan sesuatu seperti Mario asli di mana ia hanya bergerak dalam satu arah atau sesuatu ketika tidak ada resolusi ruang bebas adalah mungkin. Anda juga bisa mengurutkan daftar resolusi tabrakan dan hanya pindah ke freespace dengan jarak terpendek (saya pikir solusi itu akan menjadi yang paling disukai, meskipun saya tidak kode untuk itu).

Jeff
sumber
0

Saya hanya melakukan SAT 3 dalam 3D jadi mungkin saya tidak mendapatkan ini dengan benar. Jika saya memahami masalah Anda, itu bisa jadi karena mendapatkan kontak dengan sumbu kontak yang seharusnya tidak mungkin, sehingga pemain bertindak seperti ada lantai. Salah satu solusinya mungkin menggunakan bentuk lingkaran untuk caracter Anda, maka Anda hanya akan mendapatkan sumbu kontak dalam arah sumbu x ketika menabrak dinding.

Mikael Högström
sumber