Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Programming
Gamedevelopment

Menerapkan Tetris: Deteksi Tabrakan

Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Implementing Tetris.
Implementing Tetris: Clearing Lines

Indonesian (Bahasa Indonesia) translation by Ari Ana (you can also view the original English article)

Saya yakin itu mungkin untuk membuat permainan Tetris dengan alat gamedev point-and-click, tapi saya tidak pernah tahu caranya. Hari ini, saya lebih nyaman berpikir pada tingkat abstraksi yang lebih tinggi, di mana tetromino yang Anda lihat di layar hanyalah representasi dari apa yang terjadi dalam permainan yang mendasarinya. Dalam tutorial ini saya akan menunjukkan kepada Anda apa yang saya maksud, dengan menunjukkan cara menangani deteksi tabrakan di Tetris.

Catatan: Meskipun kode dalam tutorial ini ditulis menggunakan AS3, Anda harus dapat menggunakan teknik dan konsep yang sama di hampir semua lingkungan pengembangan permainan.


Grid

Bidang bermain Tetris standar memiliki 16 baris dan 10 kolom. Kita dapat mewakili ini dalam array multidimensi, yang berisi 16 sub-array dari 10 elemen:

Bayangkan gambar di sebelah kiri adalah tangkapan layar dari permainannya - begitulah permainan yang terlihat oleh pemain, setelah tetromino mendarat tetapi sebelum yang lain muncul.

Di sebelah kanan adalah representasi array dari kondisi permainan saat ini. Sebut saja itu landed[], karena mengacu pada semua blok yang telah mendarat. Elemen 0 berarti bahwa tidak ada blok menempati ruang itu; 1 berarti bahwa sebuah blok telah mendarat di ruang itu.

Sekarang mari kita buat O-tetromino di tengah di bagian atas bidang:

Properti shape adalah representasi array multidimensi lain dari bentuk tetromino ini. topLeft memberikan posisi blok kiri atas tetromino: di baris atas, dan kolom kelima.

Kita me-render semuanya. Pertama, kita menggambar latar belakang - ini mudah, itu hanya gambar kotak statis.

Selanjutnya, kita menggambar setiap blok dari array landed[]:

Gambar blok saya adalah 20x20px, jadi untuk menggambar blok saya bisa memasukkan gambar blok baru di (col * 20, row * 20). Detailnya tidak terlalu penting.

Selanjutnya, kita menggambar setiap blok dalam tetromino saat ini:

Kita dapat menggunakan kode gambar yang sama di sini, tetapi kita perlu memberi offset blok dengan topLeft.

Inilah hasilnya:

Implementing Tetris: Collision Detection

Perhatikan bahwa O-tetromino baru tidak muncul dalam array landed[] - itu karena, yah, itu belum mendarat.


Jatuh

Misalkan pemain tidak menyentuh kontrol. Secara berkala - katakanlah setiap setengah detik - O-tetromino perlu jatuh satu baris.

Sangat menggoda untuk hanya memanggil:

...lalu render semuanya lagi, tetapi ini tidak akan mendeteksi adanya tumpang tindih antara O-tetromino dan blok yang sudah mendarat.

Sebaliknya, kita akan memeriksa kemungkinan tabrakan pertama, dan kemudian hanya memindahkan tetromino jika itu "aman".

Untuk ini, kita perlu menentukan posisi baru potensial untuk tetromino:

Sekarang kita memeriksa tabrakan. Cara paling sederhana untuk melakukan ini adalah untuk mengulang semua ruang dalam grid yang akan diambil oleh tetromino di posisi barunya yang potensial, dan periksa array landed[] untuk melihat apakah sudah diambil:

Mari kita coba ini:

Semuanya nol! Ini berarti tidak ada tabrakan, sehingga tetromino bisa bergerak.

Kita menetapkan:

...lalu render semuanya lagi:

Implementing Tetris: Collision Detection

Hebat!


Pendaratan

Sekarang, anggaplah pemain membiarkan tetromino jatuh ke titik ini:

Implementing Tetris: Collision Detection

Kiri atas berada di {row: 11, col: 4}. Kita dapat melihat bahwa tetromino akan bertabrakan dengan balok-balok yang sudah mendarat jika jatuh lagi - tetapi apakah kode kita mengetahuinya? Mari kita lihat:

Ada 1, yang berarti ada tabrakan - khususnya, tetromino akan bertabrakan dengan blok pada landed[13][4].

Ini berarti bahwa tetromino telah mendarat, yang berarti kita perlu menambahkannya ke array landed[]. Kita bisa melakukan ini dengan perulangan yang sangat mirip dengan yang kita gunakan untuk memeriksa kemungkinan tabrakan:

Inilah hasilnya:

Implementing Tetris: Collision Detection

Sejauh ini bagus. Tetapi Anda mungkin telah memperhatikan bahwa kita tidak berurusan dengan kasus di mana tetromino mendarat di "tanah" - kami hanya berurusan dengan tetromino yang mendarat di atas tetromino lainnya.

Ada perbaikan yang cukup sederhana untuk ini: ketika kita memeriksa potensi tabrakan, kita juga memeriksa apakah posisi baru potensial dari setiap blok akan di bawah bagian bawah bidang bermain:

Tentu saja, jika ada blok di tetromino akan berakhir di bawah bagian bawah bidang bermain jika jatuh lebih jauh, kita membuat tetromino "daratan", sama seperti jika ada blok yang akan tumpang tindih dengan blok yang sudah mendarat.

Sekarang kita bisa memulai babak selanjutnya, dengan tetromino baru.


Bergerak dan Berputar

Kali ini, mari kita menelurkan J-tetromino:

Render itu:

Implementing Tetris: Collision Detection

Ingat, setiap setengah detik, tetromino akan turun satu baris. Misalkan pemain menekan tombol Left empat kali sebelum setengah detik berlalu; kita ingin memindahkan tetromino ke kiri satu kolom setiap kali.

Bagaimana kita bisa memastikan bahwa tetromino tidak akan bertabrakan dengan balok yang sudah mendarat? Kita benar-benar dapat menggunakan kode yang sama dari sebelumnya!

Pertama, kita mengubah posisi potensial baru:

Sekarang, kita memeriksa apakah ada blok di tetromino yang tumpang tindih dengan blok yang sudah mendarat, menggunakan pemeriksaan dasar yang sama seperti sebelumnya (tanpa repot-repot memeriksa apakah ada blok di bawah bidang bermain):

Jalankan melalui pemeriksaan yang sama yang biasanya kita lakukan dan Anda akan melihat bahwa ini berfungsi dengan baik. Perbedaan besar adalah, kita harus ingat untuk tidak menambahkan blok tetromino ke array landed[] jika ada potensi tabrakan - sebagai gantinya, kita seharusnya tidak mengubah nilai tetromino.topLeft.

Setiap kali pemain menggerakkan tetromino, kita harus me-render ulang semuanya. Inilah hasil akhirnya:

Implementing Tetris: Collision Detection

Apa yang terjadi jika pemain menekan kiri sekali lagi? Ketika kita memanggil ini:

...kita akan berakhir mencoba mengatur tetromino.potentialTopLeft.col ke -1 - dan itu akan menyebabkan semua masalah nantinya.

Mari kita modifikasi pemeriksaan tabrakan yang ada untuk menangani hal ini:

Sederhana - itu ide yang sama seperti ketika kita memeriksa apakah ada blok yang akan jatuh di bawah bidang bermain.

Mari kita berurusan dengan sisi kanan, juga:

Sekali lagi, jika tetromino akan bergerak di luar lapangan, kita hanya tidak mengubah tetromino.topLeft - tidak perlu melakukan hal lain.

Oke, setengah detik pasti sudah lewat sekarang, jadi mari kita biarkan tetromino itu jatuh satu baris:

Implementing Tetris: Collision Detection

Sekarang, anggaplah pemain menekan tombol untuk membuat tetromino berputar searah jarum jam. Ini sebenarnya cukup mudah untuk ditangani - kita hanya mengubah tetromino.shape, tanpa mengubah tetromino.topLeft:

Kita dapat menggunakan beberapa matematika untuk memutar isi array blok... tetapi jauh lebih sederhana hanya untuk menyimpan empat kemungkinan rotasi setiap tetromino di suatu tempat, seperti ini:

(Saya akan memberi tahu Anda cara terbaik untuk menyimpannya dalam kode Anda!)

Ngomong-ngomong, begitu kita me-render semuanya lagi, akan terlihat seperti ini:

Implementing Tetris: Collision Detection

Kita dapat memutarnya lagi (dan mari kita asumsikan kita melakukan kedua rotasi ini dalam setengah detik):

Render lagi:

Implementing Tetris: Collision Detection

Indah. Mari kita letakkan beberapa baris lagi, sampai kita mencapai kondisi ini:

Implementing Tetris: Collision Detection

Tiba-tiba, pemain menekan tombol Rotate Clockwise lagi, tanpa alasan yang jelas. Kita dapat melihat dari melihat gambar bahwa ini seharusnya tidak membiarkan apa pun terjadi, tetapi kita belum memiliki pemeriksaan untuk mencegahnya.

Anda mungkin bisa menebak bagaimana kita akan menyelesaikan ini. Kita akan memperkenalkan tetromino.potentialShape, mengaturnya sesuai dengan bentuk tetromino yang diputar, dan mencari kemungkinan tumpang tindih dengan blok yang telah mendarat.

Jika ada tumpang tindih (atau jika bentuk yang diputar sebagian keluar dari batas), kita tidak mengizinkan blok untuk berputar. Dengan demikian, itu bisa jatuh ke tempatnya setengah detik kemudian, dan ditambahkan ke array landed[]:

Implementing Tetris: Collision Detection

Luar biasa.


Menjaga Semuanya Sejajar

Untuk memperjelas, kita sekarang memiliki tiga pemeriksaan terpisah.

Pemeriksaan pertama adalah ketika tetromino jatuh, dan dipanggil setiap setengah detik:

Jika semua pemeriksaan lulus, maka kita mengatur tetromino.topLeft ke tetromino.potentialTopLeft.

Jika salah satu dari pemeriksaan gagal, maka kita membuat tetromino mendarat, seperti:

Pemeriksaan kedua adalah ketika pemain mencoba untuk memindahkan tetromino ke kiri atau ke kanan, dan dipanggil saat pemain menekan tombol gerakan:

Jika (dan hanya jika) semua pemeriksaan ini lulus, kita menetapkan tetromino.topLeft ke tetromino.potentialTopLeft.

Pemeriksaan ketiga adalah ketika pemain mencoba memutar tetromino searah jarum jam atau berlawanan arah jarum jam, dan dipanggil saat pemain menekan tombol untuk melakukannya:

Jika (dan hanya jika) semua pemeriksaan ini lulus, kita menetapkan tetromino.shape ke tetromino.potentialShape.

Bandingkan tiga pemeriksaan ini - mudah untuk membuatnya tercampur, karena kodenya sangat mirip.


Masalah lain

Dimensi Bentuk

Sejauh ini, saya telah menggunakan ukuran array yang berbeda untuk mewakili berbagai bentuk tetromino (dan rotasi berbeda dari bentuk-bentuk itu): O-tetromino menggunakan array 2x2, dan J-tetromino menggunakan array 3x2 atau 2x3.

Untuk konsistensi, saya sarankan menggunakan ukuran array yang sama untuk semua tetromino (dan rotasi padanya). Dengan asumsi Anda bertahan dengan tujuh tetromino standar, Anda dapat melakukan ini dengan array 4x4.

Ada beberapa cara berbeda untuk mengatur rotasi dalam kotak 4x4 ini; lihat Tetris Wiki untuk informasi lebih lanjut tentang berbagai permainan yang digunakan.

Tabrakan Dinding

Misalkan Anda mewakili I-tetromino vertikal seperti ini:

...dan Anda mewakili rotasinya seperti ini:

Sekarang anggaplah I-tetromino vertikal ditekan ke dinding seperti ini:

Implementing Tetris: Collision Detection

Apa yang terjadi jika pemain menekan tombol Rotate?

Nah, menggunakan kode deteksi tabrakan kita saat ini, tidak ada yang terjadi - blok paling kiri dari I-tetromino horizontal akan berada di luar batas.

Ini bisa dibilang baik-baik saja - begitulah cara kerjanya dalam versi Tetris NES - tetapi ada alternatif: memutar tetromino, dan memindahkannya satu spasi ke kanan, seperti:

Implementing Tetris: Collision Detection

Saya akan membiarkan Anda mencari tahu detailnya, tetapi pada dasarnya Anda perlu memeriksa apakah memutar tetromino akan memindahkannya keluar dari batas dan, jika demikian, gerakkan ke kiri atau kanan satu atau dua spasi seperlunya. Namun, Anda harus ingat untuk memeriksa potensi tabrakan dengan blok lain setelah menerapkan rotasi dan gerakan!

Blok Berwarna Berbeda

Saya telah menggunakan blok dengan warna yang sama di sepanjang tutorial ini untuk menjaga hal-hal sederhana, tetapi mudah untuk mengubah warnanya.

Untuk setiap warna, pilih angka untuk mewakilinya; gunakan angka-angka itu dalam array shape[] dan landed[] Anda; kemudian ubah kode rendering Anda menjadi blok warna berdasarkan nomornya.

Hasilnya mungkin terlihat seperti ini:

Implementing Tetris: Collision Detection

Kesimpulan

Memisahkan representasi visual obyek dalam permainan dari datanya adalah konsep yang sangat penting untuk dipahami; itu muncul berulang-ulang di permainan lainnya, terutama ketika berhadapan dengan deteksi tabrakan.

Dalam posting saya berikutnya, kita akan melihat bagaimana menerapkan fitur inti lain dari Tetris: menghapus baris ketika mereka terisi. Terima kasih telah membaca!

Advertisement
Advertisement
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.