Advertisement
  1. Code
  2. HTML5

Kembangkan Game Pertama Anda di Kanvas Dari Awal hingga Akhir

Scroll to top
Read Time: 52 min

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

Apakah Anda ikut serta dalam diskusi, atau membaca artikel tentang itu, Anda harus menyadari bahwa, meskipun masih merupakan spesifikasi, HTML5 siap digunakan... sekarang.

Ini tidak hanya meningkatkan struktur semantik web, tetapi juga menghidupkan API JavaScript baru untuk membuatnya lebih mudah untuk menanamkan teknologi video, audio, dan bahkan geolokasi (yang sangat menarik untuk aplikasi web seluler) dengan mudah.

Itu bukan tempat API berhenti. Mereka juga dapat digunakan untuk membangun game, dengan memanfaatkan Canvas 2D API. Dan itulah yang akan dilakukan hari ini.


Konsep

Gambar pratinjau artikel ini mungkin mengarahkan Anda ke arah apa yang akan dibuat, tetapi masih agak kabur, bukan?

Untuk menunjukkan potensi Canvas 2D API, kita akan membuat game, yang telah dibuat di Flash berkali-kali sebelumnya: game "tangkap objek yang jatuh".


Seperti yang Anda ketahui, sebagian besar permainan itu selalu terikat dengan tema tertentu, seperti menangkap buah di keranjang Anda sambil menghindari apel busuk, atau menangkap koin emas sambil menghindari batu yang tidak berharga.

Demi menjaga hal-hal sederhana dan karena sebagian besar dari Anda dengan background dalam desain web dan pengembangan sudah tahu apa kepanjangan dari RGB, kita akan menangkap balok jatuh dengan warna tertentu: red, green or blue

Kita juga akan menerapkan fitur yang agak unik: warna keranjang menunjukkan blok mana yang harus Anda tangkap. Misalnya, jika keranjang berwarna biru, Anda hanya harus menangkap balok biru.

Sekarang kita sudah siap konsep kita, kita harus memikirkan nama untuk mengikat semuanya. Pada titik ini, Anda dapat menggunakan nama-nama kreativitas dan curah pendapat Anda, seperti 'Zealof', 'Xymnia' dan 'Doogle' - tetapi ide yang lebih baik adalah dengan membuat nama yang terkait dengan permainan itu sendiri.

Karena poin utama dari permainan ini adalah 'menangkap' 'RGB' berwarna 'blok', nama yang bagus bisa menjadi sesuatu di sepanjang garis 'RGBlock' atau 'CatchBlock'. Saya memilih untuk memanggil game 'RGBCatcher', merujuk pada judul pekerjaan yang mungkin untuk pemain game.


Sketsa Sederhana

Apakah Anda sedang dalam tahap awal membangun game, atau mendesain situs web portofolio baru Anda, sketsa sederhana sangat berguna untuk dengan cepat menangkap tepi kasar sebuah ide untuk penggunaan selanjutnya.

Jauh sebelum saya mulai menulis satu baris kode, saya pertama kali membuat sketsa tentang bagaimana hal-hal akan terlihat.

Saya mengelilingi benda-benda dengan panah untuk menunjukkan kemampuan gerakan mereka, dan juga menambahkan titik-titik berwarna untuk membantu saya mengingat bahwa warna keranjang dan balok tidak seharusnya statis.

Semuanya juga harus memiliki semacam antarmuka, di mana pemain dapat membaca kesehatannya (HP) dan skor (PT) dari. Meskipun saya membuat sketsa asli dengan pensil sederhana di atas kertas, itu tampak mirip dengan gambar di bawah ini.


Jangan berlebihan membuat sketsa Anda; Anda harus menggunakannya sebagai alat untuk menangkap sisi kasar sebuah ide - bukan untuk melukis atau mendeskripsikan dengan kata-kata persis setiap langkah bagaimana hal-hal harus terlihat atau bekerja. Itulah tujuan mockup dan prototipe.


Persiapan

Bahkan sebelum kita mulai menulis satu baris JavaScript, kita harus menyiapkan tag kanvas HTML5 terlebih dahulu. canvas adalah tag HTML5 yang bekerja sama dengan Canvas 2D API. Itu benar: bekerja sama.

Ini adalah kesalahpahaman umum bahwa fungsi HTML5 baru tidak memerlukan JavaScript untuk dijalankan. HTML5 adalah — seperti versi sebelumnya — bahasa markup dan tidak mampu membuat web dinamis dengan sendirinya.


Organisasi proyek kita

Kurangnya organisasi jelas-jelas tidak boleh, jadi mari kita buat direktori baru dan menyebutnya persis sama dengan nama permainan — itu akan menampung semua file yang diperlukan untuk proyek kita.

Dalam direktori ini, Anda harus membuat direktori anak, yang disebut 'js', yang akan menampung file 'rgbcatcher.js'. Kami juga akan menulis JavaScript nanti, jadi sebaiknya Anda memiliki editor teks dengan setidaknya penyorotan sintaks dan dukungan nomor baris untuk kenyamanan Anda sendiri.

Di root direktori 'RGBCatcher', buat file teks, yang disebut 'indeks' dengan ekstensi HTML biasa dan buka dengan editor teks favorit Anda — index.html akan berfungsi sebagai titik awal untuk game kita.

HTML

Tidak ada hal-hal mewah yang terjadi dengan markup - hanya doctype HTML5, referensi ke rgbcatcher.js, dan tag kanvas dengan gaya yang sangat terbatas diterapkan harus melakukan trik.

Seperti yang Anda lihat, doctype HTML5 secara signifikan lebih sederhana, dibandingkan dengan sebagian besar doctype aliran utama saat ini. Di antara hal-hal lain yang bermanfaat, DOCTYPE baru ini memungkinkan untuk instantiasi lebih cepat dari dokumen HTML yang sesuai standar.


JavaScript

Dalam sketsa, setiap objek instantiated memiliki tanda silang di dalamnya. Ingatlah ini: kita dapat dengan mudah membuat daftar definisi fungsi mana yang akan dibutuhkan:

  • Indikator kesehatan (dapat dihitung)
  • Penghitung skor (dapat dihitung)
  • Sebuah blok (bergerak)
  • Keranjang (dikontrol oleh pemain, juga dapat digerakkan)

Jadi mengapa hanya ada satu blok dalam daftar, sementara kita dapat melihat lima di sketsa? Meskipun JavaScript berbasis prototipe, kita dapat membuat instance banyak blok dari satu definisi blok dasar.


Pembungkus Obyek

Sekarang kita sudah menyiapkan daftar objek kita, seharusnya tidak terlalu sulit untuk membuat pembungkus untuk mereka.

Tunggu — objek blok dan keranjang keduanya bertipe 'bergerak' (koordinatnya dapat berubah), jadi bukankah berguna memiliki objek bergerak dasar, yang nantinya dapat diwarisi dari objek blok dan keranjang?

Objek blok dan keranjang bukan satu-satunya objek yang memiliki fungsi tertentu yang sama — indikator kesehatan dan penghitung skor keduanya dirancang untuk melacak nilai tertentu: skor dan kesehatan, masing-masing.

Itu dia. Meskipun mereka tidak memiliki fungsi sama sekali, pembungkus kita selesai!



Definisi Global

Sebelum melangkah lebih jauh, kita membutuhkan dua hal: beberapa variabel global yang dapat diakses dari fungsi apa pun yang memerlukannya, dan pembungkus global. Wrapper global ini berfungsi sebagai pengendali utama untuk game.

Secara umum, definisi global adalah hal yang buruk, karena JavaScript hanya memiliki satu namespace tunggal. Ini membuatnya lebih mudah bagi nama variabel dan fungsi untuk bertabrakan di antara berbagai skrip pada halaman yang sama, tetapi karena game ini cukup banyak dijalankan sebagai stand-alone, kita tidak perlu terlalu khawatir tentang hal itu.

Semua variabel global akan diletakkan di bagian atas file rgbcatcher.js. Pembungkus RGBCatcher global akan ditempatkan di bagian bawah.

Kita juga mendefinisikan fungsi rand global baru, yang akan memudahkan kita untuk mengambil angka acak dalam rentang tertentu. Ini akan, misalnya, digunakan untuk memilih warna acak dari array RGBCatcher.colors.


Fungsi Basis Bergerak

Karena baik keranjang dan objek blok adalah benda bergerak, yang berarti bahwa koordinatnya tidak konstan, pertama-tama kita akan menulis objek dasar yang dapat mereka warisi.

Objek dasar bergerak hanya boleh berisi fungsionalitas, yang akan hadir di kedua blok dan definisi fungsi keranjang.

Constructor

Konstruktor adalah rutin, yang dipanggil segera setelah objek baru dipakai dan sebelum objek memiliki prototipe yang ditugaskan padanya. Ini membuat konstruktor sangat berguna untuk menginisialisasi variabel spesifik objek, yang kemudian tersedia dalam lingkup objek.

Karena objek keranjang dan blok akan menampung properti yang berbeda, kita akan menulis konstruktor yang menerima array dan kemudian menggunakan array itu untuk mengatur variabel objek tertentu.

Memperbarui objek Movable

Proses pembaruan objek bergerak, yang terdiri dari fase gerakan dan menggambar, seharusnya hanya terjadi ketika objek bergerak masih hidup.

Karena gerakan aktual dan proses menggambar objek bergerak mungkin tergantung pada pewarisnya, objek bergerak dasar seharusnya tidak mendefinisikan mereka kecuali semua pewaris berbagi pembaruan atau metode menggambar yang sama.


Basket

Sekarang kita telah mendefinisikan objek bergerak, kita hanya perlu menulis metode move dan draw tambahan untuk objek keranjang yang diwarisi darinya.

Variabel khusus keranjang

Sebelum kita mulai dengan metode objek keranjang, kita harus terlebih dahulu mendefinisikan beberapa variabel yang secara spesifik terkait dengan objek ini. Variabel-variabel ini akan dipegang oleh pembungkus RGBCatcher.

Variabel basket akan menyimpan instance objek keranjang. Variabel basketData adalah array yang menyimpan data tentang keranjang, seperti tinggi dan kecepatan gerakan horizontal.

Constructor

Karena basis bergerak sudah memiliki konstruktor dan metode pembaruan yang diperlukan untuk fungsi basket, kita mewariskan jauh dari mengimplementasikannya.

Mengatur Ulang Basket

Kita ingin memusatkan keranjang di bagian bawah layar, dan mengubah warna keranjang segera setelah permainan atau level baru dimulai.

Dengan membagi lebar keranjang dengan dua dan mengurangi nilai ini dari lebar kanvas, juga dibagi dua, sebagai hasilnya, kita akan mendapatkan basket yang berpusat sempurna.

Untuk menempatkan keranjang di bagian bawah layar, kita mengatur koordinat y ke ketinggian keranjang, dikurangi dari ketinggian kanvas.

Mengatur ulang warna basket sedikit lebih sulit.

Kita menggunakan loop sementara yang secara acak akan memilih warna dari array RGBCatcher.color publik pada setiap putaran.

Segera setelah warna dipilih yang tidak sama dengan warna keranjang yang lama, loop berhenti berputar dan oldColor baru ditugaskan.

Memperbarui Basket

Karena objek yang bergerak telah membawa fungsionalitas untuk metode update, kita hanya perlu mendefinisikan metode tertentu untuk memindahkan dan menggambar keranjang.

Metode yang akan memindahkan keranjang, akan, tergantung pada input pengguna, menambah atau mengurangi kecepatan gerakan horizontal (basket.xSpeed) dari koordinat x saat ini keranjang.

Metode pemindahan juga bertanggung jawab untuk memindahkan keranjang kembali ke posisi terbaru yang memungkinkan jika keranjang bergerak keluar dari elemen kanvas viewport — ini mengharuskan kita untuk menerapkan rutin yang sangat sederhana untuk deteksi tabrakan.

Deteksi tabrakan tidak boleh diimplementasikan hanya dengan memeriksa apakah koordinat objek cocok dengan ekspresi tertentu. Ini mungkin bekerja untuk grafik yang 1px demi 1px, tetapi tampilan grafis dari sesuatu yang lebih besar dari itu akan benar-benar mati karena harus ada juga akun dengan lebar dan tinggi.

Itulah sebabnya sebagian besar waktu Anda harus mengurangi atau menambahkan bentuk lebarnya atau tinggi masing-masing koordinat x atau y untuk mencocokkan representasi grafis dari sebuah tabrakan.

Sekarang pengguna dapat memindahkan keranjangnya, satu-satunya hal yang masih harus kita lakukan adalah menulis metode yang memiliki kemampuan untuk menggambar keranjang di layar — ini adalah tempat Canvas 2D API melompat masuk.

Anda mungkin berpikir bahwa memanfaatkan API ini sangat canggih, tetapi sebenarnya tidak! Canvas 2D API dirancang sesederhana mungkin, namun sefungsional mungkin.

Kita hanya memerlukan dua dependensi Canvas 2D API: properti fillStyle dan metode fillRect.

Properti fillStyle digunakan untuk mendefinisikan warna isian untuk bentuk.
Nilai harus mengikuti spesifikasi CSS3 untuk warna — ini berarti Anda diizinkan untuk menggunakan 'hitam' tetapi juga setara dengan HEX, '#000' — tetapi juga bekerja dengan gradien dan pola tetapi kita akan menggunakan warna isian sederhana.w

Metode fillRect menggambar persegi panjang yang diisi, dengan memanfaatkan fillStyle sebagai warna isiannya, pada posisi (x, y) dan lebar dan tinggi piksel yang ditentukan.

Perhatikan bahwa parameter fillRect yang diperlukan dapat ditemukan sebagai properti di objek keranjang yang dipakai, jadi kita bisa menggunakan kata kunci this dalam kombinasi dengan nama parameter.

Definisi fungsi akhir

Itu dia; kita memiliki seluruh objek keranjang yang berjalan dan berjalan.

Yah, saya tidak akan menyebutnya berjalan, jadi mari kita atur lingkaran permainan dan berbagai elemen inti dari permainan kita, sehingga kita dapat menggunakan keranjang ini untuk digunakan!


RGBCatcher Wrapper

Untuk benar-benar mengimplementasikan fungsi dan prototipe yang baru saja ditulis, mereka harus dipakai dan dipanggil di suatu tempat. Inilah yang akan ditangani oleh penangan utama permainan: membuat instance dan memanggil hal-hal yang tepat pada waktu yang tepat.

Metode yang dijalankan

Metode run publik dari pembungkus RGBCatcher, akan menginisialisasi komponen game (seperti Canvas 2D API, sebuah instance dari objek keranjang dan sebagainya).
Ini juga akan mengatur pendengar acara global untuk acara keyup dan keydown sehingga penekanan tombol saat ini dapat dengan mudah diambil dari array global keyOn.

Menyetel ulang game

Karena kita hanya memiliki satu objek terkait permainan untuk diatur ulang sejauh ini, yang merupakan objek basket, kita hanya perlu memanggil metode pengaturan ulang objek ini untuk mengatur ulang permainan.

Perhatikan bahwa metode ini hanya boleh dipanggil pada awal permainan baru. Karena kita belum memiliki manajemen level, untuk saat ini dipanggil dari fungsi run RGBCatcher.

Siklus game

Siklus game bertanggung jawab untuk memperbarui dan menggambar ulang semua objek permainan hingga peristiwa tertentu terjadi, seperti pengguna kehabisan kesehatan.

Siklus game memiliki beragam format dan ukuran, tetapi urutan umum loop game adalah memeriksa input, memperbarui, dan memindahkan objek game, membersihkan layar, dan menggambar ulang semua objek game ke layar.


Dengan hanya memanggil metode update objek keranjang, yang sudah memproses sebagian besar langkah-langkah yang ditemukan di loop game.

Satu-satunya baris kode tambahan untuk ditulis adalah baris yang membersihkan layar. Karena layar kita adalah elemen kanvas, API 2D Kanvas diperlukan untuk mencapai ini.

Menghapus kanvas dengan memanfaatkan Canvas 2D API dilakukan melalui metode clearRect. Ia menerima empat parameter: koordinat x dan y untuk mulai membersihkan dari dan lebar dan tinggi untuk dihapus.

Karena kita perlu menghapus persegi panjang yang tumpang tindih dengan seluruh kanvas, kita mulai dari titik (0, 0) dan mengatur tinggi dan lebar masing-masing tinggi dan lebar elemen kanvas.

Sekarang setelah siklus game kita membersihkan kanvas di setiap putaran, juga disebut bingkai, kita hanya perlu memanggil metode pembaruan objek keranjang karena menangani proses pemindahan, pembaruan, dan menggambar ulang dengan sendirinya.

Titik masuk

Satu-satunya hal yang masih hilang untuk melakukan uji coba pertama game ini, adalah titik masuk untuk loop game.

Satu-satunya tujuan entry point adalah untuk memulai loop game dan menentukan interval untuk setiap loop putarannya — setInterval adalah persis apa yang kita butuhkan.

Seperti yang mungkin Anda perhatikan, begitu dimasukkan, loop game kita berjalan tanpa batas. Kita pasti akan mengubahnya nanti, tetapi untuk saat ini kita masih dalam tahap awal proses pengembangan.


Ayo, Ayo!

Sekarang setelah objek master RGBCatcher wrapper dan keranjang telah ditentukan, akhirnya kita dapat menguji game prematur!

Karena permainan kami tergantung pada kanvas elemen, kita harus menunggu sampai ia dituliskan sebagai sebelum kita sebut RGBCatcher publik menjalankan metode.
Ini bisa dilakukan dengan memasukkan file JavaScript setelah markup elemen kanvas, tetapi jika Anda ingin menjaga JavaScript Anda di elemen-head, cukup lampirkan metode run ke window acara onload nya.

Jalankan file index.html yang terletak di direktori RGBCatcher dan cobalah untuk memindahkan keranjang dengan memanfaatkan tombol panah kiri dan kanan.

Coba juga untuk menyegarkan halaman beberapa kali untuk memeriksa apakah warna keranjang benar-benar berubah atau tidak. Jangan khawatir jika Anda melihat warna yang berulang — warna yang lama tidak disimpan pada refresh halaman.

Jelas itu belum terlalu spektakuler, jadi jangan ragu untuk melanjutkan karena kami akan menambahkan beberapa balok jatuh.



Blok

Permainan menangkap-benda-jatuh tidak benar-benar layak dimainkan tanpa benda jatuh untuk ditangkap jadi mari kita lanjutkan dan buat balok itu jatuh!

Kita akan mulai dengan menuliskan kode untuk objek blok dan dalam waktu singkat Anda akan melihat blok merah, hijau dan biru jatuh di layar Anda.

Blok variabel tertentu

Sama seperti objek keranjang, objek blok membutuhkan array yang diisi dengan data untuk menyimpan properti spesifik blok, seperti lebar dan kecepatan gerakan vertikal.
Array data ini masuk dalam pembungkus RGBCatcher.

Jadi mengapa ada, tidak seperti variabel basket, tidak ada variabel block yang akan menampung instance dari objek blok?
Karena level harus mengandung lebih dari satu blok untuk ditangkap.

Bahkan, kita akan menggunakan semacam manajer blok yang akan mengelola blok — lebih lanjut tentang itu nanti.

Constructor

Konstruktor objek blok kita persis sama dengan konstruktor objek keranjang.

Perhatikan bagaimana kita akan memiliki beberapa baris kode duplikat jika kita tidak menggunakan definisi objek bergerak dasar?

Menyetel Ulang Block

Karena kita ingin mencegah agar semua blok jatuh pada posisi yang persis sama, kita menggunakan fungsi rand untuk meletakkan blok pada posisi horizontal acak.

Alih-alih memiliki metode resetPosition, kita akan memanggil metode yang mencapai initPosisi posisi acak karena metode ini adalah tentang menginisialisasi posisi, bukan menyetel ulang.

Inisialisasi? Bukankah konstruktor yang seharusnya melakukan itu? Ya, jadi kita hanya akan memanggil metode initPosition sekali, di konstruktor.

Sebuah blok sekarang akan secara otomatis menginisialisasi posisinya pada instantiation, tetapi belum menginisialisasi warnanya.

Pertama, kita harus mengubah konstruktor fungsi blok sehingga, di samping initPosition, panggilan akan dibuat ke initColor saat instantiasi.

Untuk saat ini, ini akan membuang "Object# tidak memiliki metode 'initColor' "TypeError jadi mari kita tambahkan metode initColor ke prototipe.

Memperbarui Block

Prototipe yang dapat dipindah-pindah telah menghadirkan fungsionalitas untuk metode pembaruan kolektif, jadi sekali lagi itu sesuatu yang tidak perlu kita khawatirkan.

Karena tidak diperlukan input untuk blok jatuh, metode yang membuat blok bergerak, sangat lurus ke depan: terus menambahkan kecepatan jatuh vertikal ke posisi vertikal saat ini.

Satu-satunya yang tersisa untuk menulis untuk objek blok kita adalah metode draw, yang merupakan tugas lain untuk Canvas 2D API.

Untuk menggambar blok, pertama-tama kita harus menetapkan warna isian dan kemudian kita harus menggambar persegi panjang dengan parameter yang diambil dari properti blok.
Kedengarannya familiar? Itu harus. Kita melakukan trik yang persis sama dengan metode draw objek keranjang, ingat?

Karena objek keranjang dan blok sama-sama dapat bergerak, kita hanya akan memindahkan metode draw keranjang ke prototipe bergerak sehingga semua pewaris akan berbagi metode draw ini.

Definisi fungsi akhir

Blok-blok itu tidak akan jatuh sendiri jadi mari kita lanjutkan dan menambahkan penanganan blok ke pembungkus RGBCatcher.


Menangani Block

Meskipun basket mampu bergerak tanpa bantuan pengendali yang dikendalikan komputer, satu blok jelas tidak.

Ini membutuhkan penyelia atau lebih tepatnya seorang manajer, yang, antara lain, dapat menghapus blok dari layar segera setelah mereka menyentuh tanah. Pengawas ini akan menemukan tempatnya di pembungkus utama RGBCatcher.


  • Initialize: Inisialisasi variabel terkait khusus ke blok, seperti variabel yang menunjukkan berapa banyak blok yang masih ada di layar.
  • Reset: Reset semua variabel initialized ke nilai default.
  • Perbarui block: Segera setelah inisialisasi selesai, loop game dimasukkan dan kita akan mulai dengan looping melalui semua blok yang tersedia saat ini dan memperbaruinya.
  • Periksa tabrakan: Untuk setiap blok kita harus memeriksa apakah sedang bertabrakan atau tidak dan melakukan tindakan spesifik pada tabrakan tertentu.
  • Tambahkan blok jika diperlukan: Ketika semua blok berhasil diperbarui dan tumbukan telah ditangani, blok baru harus muncul jika ini diperlukan.

Blok penanganan variabel tertentu

Kita membutuhkan lima variabel lagi untuk menangani blok. Semuanya masuk dalam definisi fungsi RGBCatcher sebagai properti pribadi.

Reset

Pembungkus objek RGBCatcher sudah memiliki metode resetGame. Kita sekarang hanya perlu menambahkan nilai default untuk variabel yang ditentukan di atas, sehingga mereka direset pada awal permainan baru.

Perbarui block

Fase blok pembaruan muncul pada perulangan melalui semua blok dan memperbarui mereka. Ini juga bertanggung jawab untuk memulai fase selanjutnya dari manajemen blok yang terdiri dari memanggil metode untuk menangani deteksi tabrakan.

Sekarang kita menuju suatu tempat. Setiap blocks dalam variabel blok diperbarui dengan memanfaatkan metode update objek blok.

Ketika blok telah diperbarui, itu akan mendorong untuk metode checkCollision yang kemudian akan menangani deteksi tabrakan.

Periksa tabrakan

Deteksi tabrakan adalah salah satu bagian tersulit dalam pengembangan game. Meremehkannya, mungkin menghasilkan hasil yang tidak terduga.

Pernahkah Anda menemukan permainan di mana Anda bisa berjalan menembus tembok dan bisa menembak musuh tanpa membidik mereka dengan benar? Salahkan pengembang yang bekerja pada deteksi tabrakan!

Game-game itu mungkin 3D, tapi, beruntung bagi kita, kita hanya perlu khawatir tentang dua dimensi yang mungkin bertabrakan satu sama lain sehingga praktis ada dimensi keseluruhan yang tidak salah!

Dalam permainan RGBCatcher, hanya ada total empat tabrakan yang perlu dikhawatirkan dan kita sudah berurusan dengan dua tabrakan pertama — ingat kemungkinan tabrakan antara basket dan batas kanan atau kiri layar?

Dua tabrakan terakhir melibatkan balok jatuh dan apakah mereka mengenai basket atau tanah.

Sebelum memeriksa apakah ada tabrakan aktual dengan tanah atau basket, kita akan memeriksa apakah blok telah lewat atau saat ini berada di garis y tempat basket berada.

Seperti yang Anda lihat pada gambar di bawah ini, mendasarkan deteksi tabrakan hanya pada objek koordinat mereka adalah hal yang buruk karena representasi visual dari blok telah mengenai basket sebelum koordinat cocok dengan tabrakan.


Ketika kita yakin bahwa blok secara visual sama atau pada koordinat y yang lebih tinggi daripada keranjang, kita dapat dengan aman memeriksa apakah koordinat x dari blok berada dalam kisaran yang benar.

Selain koordinat y, tidak hanya ada satu tempat di mana sebuah blok dapat bertabrakan secara horizontal dengan keranjang. Itu sebabnya kita perlu memeriksa apakah blok berada dalam kisaran lebar total keranjang untuk menentukan apakah kita sedang berhadapan dengan tabrakan atau tidak.

Kisaran keranjang tidak dapat dijelaskan hanya dalam satu nilai statis, jadi kita akan menggunakan algoritma yang sangat dasar.

Algoritma ini akan menentukan apakah posisi x blok lebih besar atau sama dengan posisi x keranjang dan apakah posisi x blok ditambah lebarnya lebih rendah dari posisi x keranjang plus lebarnya.


Mengedit dan menambahkan beberapa variabel game

Sebelum kita melanjutkan, pertama-tama kita harus menambahkan dan mengedit beberapa variabel yang ditemukan dalam lingkup pembungkus RGBCatcher.

Variabel yang akan diedit adalah variabel blockData. Kita akan menambahkan properti blok yang disebut kekuatan - nilai ini akan berdampak pada kesehatan pengguna jika pengguna melewatkan blok berwarna dengan benar atau jika menangkap blok yang salah warna.

Di sisi lain, jumlah kekuatan akan ditambahkan ke skor pengguna jika pengguna menangkap blok yang memiliki warna yang sama dengan basket

Dua variabel lain yang ditambahkan disebut health dan score. Variabel-variabel ini akan menahan objek yang mewakili grafik kesehatan grafik dan penghitung skor nanti, tetapi untuk saat ini mereka hanyalah nilai integer sederhana.

Menangkap satu blok

Karena tujuan permainan kita mengharuskan pengguna hanya menangkap balok, yang memiliki warna yang sama dengan keranjang, pertama-tama kita akan membandingkan warna balok dengan warna keranjang.

Jika mereka sama, kita mendapat tangkapan yang benar dan skor harus meningkat dengan kekuatan blok. Di sisi lain, jika blok yang salah warna menurunkan kesehatan pengguna dengan kekuatan blok.

Dalam kedua kasus, blok tersebut harus menghilang dari layar dan variabel blockOnScreen akan berkurang dengan satu

Hilang satu blok

Jika pengguna melewatkan blok yang berwarna dengan benar, kekuatan blok harus ditimbulkan untuk kesehatan pemain. Namun, tidak ada yang salah dengan melewatkan blok warna yang salah dan jika itu terjadi permainan harus dilanjutkan tanpa tindakan lebih lanjut.

Berlawanan dengan menangkap blok, blok seharusnya tidak segera menghilang dari layar. Pertama-tama harus jatuh ke bawah port tampilan kanvas dan kemudian dihapus dari array blocks.

Tambahkan blok jika diperlukan

Jadi bagaimana cara kerja metode addBlock Anda?

Pertama-tama memeriksa apakah jumlah blok yang diperlukan untuk level saat ini (blokPerLevel * level) sama dengan jumlah blok yang telah dihasilkan (blocksSpawned).

Jika tidak, objek blok baru muncul, itu akan ditambahkan ke array blocks dan blocksSpawned dan blocksOnScreen variabel akan ditingkatkan dengan satu.

Jika ya, ekspresi dijalankan untuk menentukan apakah masih ada blok pada layar (blocksOnScreen) yang harus mendarat di suatu tempat terlebih dahulu.
Jika ini bukan masalahnya dan blockOnScreen == 0, kita dapat mengatakan bahwa level telah selesai.

Metode addBlock mengembalikan true jika masih ada blok untuk diproses dan false jika jumlah blok yang benar telah dihasilkan dan dihapus dari layar.


Layar Info

Kita dapat mengimplementasikan fungsi yang baru saja ditulis di gameloop dan mulai bermain segera, tetapi bukankah jauh lebih baik untuk memiliki layar judul yang menunggu respons pengguna alih-alih segera mulai dengan blok jatuh di layar?

Mari kita menulis fungsi yang menampilkan layar judul mewah dan menunggu input dari pengguna — bilah ruang terdengar sesuai.

Kita bisa menggunakan Canvas 2D API untuk merender layar judul, tapi mengapa tidak menggunakan tag HTML dan menggunakan JavaScript untuk mengubahnya.

Memperbarui HTML

Layar judul akan diletakkan di elemen div umum yang ditandai dengan ID info karena akan berfungsi sebagai layar info juga, tidak hanya untuk menampilkan layar judul.

Dengan dimensi 200px * 26px, kita menggunakan posisi absolut dan cukup menghitung margin 'atas' dan 'kiri' dari elemen info untuk memusatkannya dengan baik di atas elemen kanvas.

Untuk posisi teratas kita menambahkan margin atas elemen #canvas ke tinggi total, minus ketinggian elemen info dan membaginya dengan dua.
Kita melakukan hal yang sama untuk posisi kiri, kecuali bahwa alih-alih menggunakan ketinggian, kita menggunakan lebar #canvas dan elemen #info untuk menghitung posisi yang benar.

Sekarang kita mendapatkan HTML dan CSS kita disortir lagi, kita dapat kembali ke proses yang jauh lebih menarik dari penulisan kode yang menampilkan layar judul sebenarnya.

Fungsi titleScreen

Fungsi titleScreen adalah fungsi anak (metode) pembungkus fungsi RGBCatcher.
Sebelum menuliskannya, kita perlu menambahkan dua variabel pribadi — info dan infoScreenChange.

info memegang objek DOM yang memberi kita tool yang diperlukan untuk mengubah elemen info.
Boolean infoScreenChange, yang defaultnya benar, membantu kita untuk menentukan apakah layar info harus diperbarui atau tidak.

Ringkasnya: jika layar info belum diperbarui (infoScreenChange === true), lakukanlah.
Kemudian tunggu saja tekan pada bilah spasi (keyOn[32]) untuk menyembunyikan layar info, reset game dan masukkan loop game.

Seharusnya ada beberapa perubahan pada metode run untuk mengatur variabel info lokal diatur dan mengaitkan setInterval ke layar judul alih-alih lingkaran permainan.

Jangan ragu untuk mencobanya.
Meskipun belum ada blok yang jatuh, kita sekarang memiliki layar judul yang sedang ditampilkan sebelum permainan dimulai dan menghilang segera setelah pengguna menekan spasi.



Manajemen Level

Sekarang kita punya layar judul dan berjalan, sudah waktunya untuk membiarkan blok jatuh.

Sedikit ke belakang, Anda mungkin telah memperhatikan variabel level lokal yang belum terdefinisi dalam metode addBlock pribadi RGBCatcher. Variabel ini merupakan permintaan rutin manajemen level.

Mari kita definisikan bersama-sama dengan variabel baru yang disebut levelUp. Dengan boolean ini kita dapat menentukan apakah pengguna baru saja menyelesaikan level atau tidak.

Melihat kembali skema pengelolaan blok, kita melihat lingkaran pembaruan, pemeriksaan tabrakan dan penambahan blok jika ini diperlukan. Karena game kita sudah memiliki loop yang berputar, yang merupakan loop game, pola yang berulang masuk ke sana.

Tapi blok apa yang akan diperbarui jika tidak ada panggilan yang dilakukan ke fungsi addBlock?

Menambahkan fungsi timer

Kapan blok baru harus jatuh, tergantung pada variabel blocksSpawnSec. Kita akan menambahkan timer sederhana untuk diperiksa agar kita dapat menentukan apakah kita harus memanggil fungsi addBlock atau tidak.

Variabel yang diperlukan untuk mencapai ini, disebut frameTime dan startTime.

frameTime akan ditetapkan pada setiap putaran loop game sedangkan startTime hanya harus ditetapkan pada awal timer baru. Timer pertama ini harus mulai berjalan pada awal permainan baru.

Kita sudah memiliki fungsi yang disebut resetGame, yang disebut pada awal permainan baru, jadi kami mendefinisikan variabel startTime di sana. Sementara kita berada di dalamnya, kita mungkin juga menambahkan reset untuk variabel level.

Perhatikan bahwa fungsi yang digunakan untuk mengambil waktu saat ini, getTime, mengembalikan nilai integer yang mewakili waktu saat ini dalam milidetik sejak tahun 1970.

Sekarang kita memiliki nilai startTime awal, kita dapat dengan mudah mengetahui berapa banyak milidetik yang telah berlalu dengan hanya mengekstraksi nilai ini dari frameTime saat ini.

Jadi setelah memanggil metode updateBlocks, kita memeriksa apakah waktu frame saat ini lebih besar dari waktu mulai ditambah detik setelah mana blok baru harus muncul. Jika ini masalahnya, kita menyetel ulang timer dan melakukan panggilan ke fungsi addBlock — tergantung pada nilai baliknya, tindakan yang sesuai akan dilakukan.

Naik level

Jika fungsi addBlock mengembalikan false, kita dapat mengatakan bahwa level saat ini telah selesai, jadi mengatur variabel levelUp menjadi true.

Kita juga meningkatkan kesulitan permainan dengan sedikit mengurangi waktu antara blok jatuh (blocksSpawnSec) dan sedikit meningkatkan kecepatan di mana blok jatuh (blockData['ySpeed']). In-and decrements ini adalah bagian dari permainan, jangan ragu untuk menyesuaikannya nanti jika Anda pikir ini terlalu rendah atau terlalu tinggi.

Ketika level telah selesai, beberapa variabel harus direset. Rutin ini tidak persis sama dengan prosedur reset game, jadi menulis fungsi yang pas untuk itu adalah hal berikutnya yang akan kita lakukan.

Mengatur ulang level

Mengingat konsep permainan, warna dan posisi basket harus diatur ulang di awal level baru. Untuk memberi penghargaan kepada pemain karena menyelesaikan level, kita akan mengatur ulang kesehatannya.

Jelas, variabel blocksSpawned, blocksOnScreen dan blocks juga harus di-reset.

Game Over

Sekarang kita memiliki implementasi resetLevel, kita dapat melanjutkan bekerja pada loop game.

Apa yang masih hilang darinya adalah pemeriksaan kesehatan pengguna untuk menentukan apakah kesehatannya masih cukup untuk melanjutkan, dan rutin yang membuat pengguna tahu bahwa level baru sedang dimulai.

Hal pertama relatif sederhana, jadi mari kita mulai dengan itu. Pada dasarnya, kita hanya perlu memeriksa apakah kesehatan pemain lebih rendah dari 1.

Jadi bagaimana seharusnya prosedur game-over dilaksanakan? Pada titik di mana pengguna memiliki kurang dari 1/100 HP, gim harus berakhir dan game pesan harus ditampilkan.

Ini paling baik dilakukan dengan berhenti dari loop game saat ini dan memasukkan game baru di atas loop yang akan mem-flash pesan untuk jumlah waktu tertentu, tiga detik terdengar baik, setelah itu layar judul ditampilkan lagi.

Fungsi gameOverScreen baru harus ditentukan yang pertama membersihkan seluruh kanvas, menampilkan pesan permainan-lebih-dan setelah tiga detik berlalu, kembali ke layar judul.

Game-over-message akan diletakkan di layar info. Menampilkan pesan hanya selama tiga detik mudah dicapai dengan menggunakan fungsi penghitung waktu yang harus Anda kenal sekarang.

Bersiaplah untuk level 2!

Apa yang hilang dari loop game kita yang diperbarui adalah rutin yang menangani flashing pesan naik level.
Kita sudah memiliki variabel yang disebut levelUp yang membantu kita untuk menentukan apakah pesan harus ditampilkan atau tidak.

Jadi kita cukup menyalin kode gameOverScreen ke if-statement, ubah pesan yang akan di-flash dan tindakan dilakukan setelah tanda tiga detik tercapai.

Jangan ragu untuk mencoba game ini lagi. Ini cukup fungsional, kecuali bahwa masih ada dua hal yang hilang: penghitung skor dan bar kesehatan. Kita membuat kemajuan, sekarang!



Fungsi Basis yang Dapat Dihitung

Penghitung skor dan bilah kesehatan memiliki satu kesamaan: menghitung nilai tertentu. Oleh karena itu adalah ide yang baik bagi mereka untuk memiliki objek yang dapat mereka warisi dari: objek dasar yang dapat dihitung — seperti yang dilakukan dengan definisi dasar bergerak untuk objek keranjang dan blok.

Dimulai dengan fakta bahwa objek kesehatan dan skor harus menyediakan kita dengan metode untuk mengubah nilai mereka, mereka juga harus memiliki metode yang mengembalikan nilai saat ini dari objek yang dipakai dan mereka berdua akan memiliki pembaruan dan gerakan rutin.

Construktor

Construktor dari basis yang dapat dihitung, seharusnya hanya mendefinisikan properti yang dibagikan oleh semua pewaris.

Ini adalah x dan y untuk penentuan posisi, properti value yang menyimpan nilai yang dapat dihitung (seperti jumlah kesehatan), properti targetValue, dan properti speed.

Properti speed dan targetValue akan digunakan untuk animasi grafis, tetapi kita akan kembali ke nanti.

Metode reset harus dideklarasikan oleh pewaris yang akan mengatur properti objek ke nilai kustom untuk inisialisasi.

Memperbarui objek yang Dapat Dihitung

Metode pembaruan dari prototipe yang dapat dihitung identik dengan metode pembaruan dari prototipe yang dapat bergerak kecuali bahwa itu tidak memerlukan pemeriksaan 'masih hidup'.

Mengatur nilai objek yang Dapat Dihitung

Properti TargetValue dan value akan digunakan untuk melakukan animasi grafis dasar di mana bilah kesehatan atau penghitung skor meluncur dari value lamanya ke targetValue baru.

Hal ini dicapai dengan tidak secara langsung mengatur nilai properti, tapi dengan menggunakan sub-stasiun yang disebut targetValue yang dapat kita gunakan untuk membuat animasi.

Dengan secara langsung menambahkan jumlah perubahan yang diinginkan ke nilai target, kita juga dapat menggunakan jumlah negatif. Ini memberi kita kemampuan untuk mengurangi, tetapi juga menambahkan jumlah tertentu ke nilai target.

Memindahkan objek yang Dapat Dihitung

Proses perpindahan objek yang dapat dihitung bukan tentang mengubah koordinatnya, seperti yang dilakukan dengan blok dan move rutin keranjang, tetapi tentang mengubah value saat ini sehingga pada akhirnya akan sama dengan targetValue.

Praktis ini akan menghasilkan proses properti value sedikit meningkat atau menurun nilainya sampai pada nilai yang sama dengan targetValue.

Karena properti value akan digunakan untuk menggambar skor atau bilah kesehatan, mengubahnya dari waktu ke waktu alih-alih menetapkan secara langsung, menghasilkan animasi.

Pertama-tama kita harus menentukan apakah nilainya sudah sama dengan nilai target. Jika ini masalahnya, tidak ada yang terjadi. Jika tidak, kecepatan harus ditambahkan (value < targetValue) dari nilai aktual (value > targetValue).

Segera setelah perbedaan antara target dan nilai aktual lebih rendah dari kecepatan animasi, nilai tersebut harus ditetapkan ke nilai target karena menambah atau mengurangi kecepatan dari nilai akan lebih dari cukup.

Definisi fungsi akhir

Sekarang kita memiliki basis definisi fungsi yang dapat dihitung, pewaris hanya perlu mendefinisikan metode reset dan draw... dan siap untuk digunakan! Seberapa nyaman itu?


Objek Kesehatan

Jelas, objek kesehatan bertanggung jawab untuk melacak titik kesehatan pengguna dan menggambar bar kesehatan ke layar.

Karena fungsi terhitung dasar sudah menyediakan update, change dan get, kita hanya perlu mendefinisikan metode reset dan draw.

Constructor

Meskipun value dan targetValue properti dari objek ini harus diatur ulang dalam metode reset, konstruktor mendefinisikan statis x dan y properti.


Jika kita melihat kembali sketsa itu, kita melihat bahwa kita berencana untuk menempatkan bar kesehatan di sudut kanan atas dengan beberapa margin tambahan dari batas kanvas.

Ini dicapai dengan menyetel properti x ke lebar kanvas dikurangi dengan lebar bar kesehatan (52px) dan margin kanan yang diinginkan (10px). Kedua, kita akan mengatur properti y menjadi 10, yang tidak lebih dari margin atas.

Kita juga melakukan panggilan ke metode reset yang belum ditentukan yang akan menetapkan properti value dan targetValue saat instantiasi.

Menyetel ulang objek Kesehatan

Objek terhitung dasar sudah mendefinisikan beberapa properti, tetapi karena tidak semua pewaris berbagi nilai properti yang persis sama, pewaris metode reset akan mengatur properti tersebut ke nilai yang benar.

Karena kita ingin memulai permainan dengan animasi pengisian health bar, kita akan menetapkan nilai awal kesehatan pada 1 dan nilai target pada 100 alih-alih membiarkannya pada nilai default.

Drawing Health object

Bilah kesehatan terdiri dari tiga gambar yang berkolaborasi; sebuah wadah, health bar aktual yang lebarnya berfluktuasi dan sepotong kecil teks untuk interface.

Container

Wadah ini cukup sederhana untuk digambar meskipun memperkenalkan metode baru Canvas 2D API: metode strokeRect; metode untuk menggambar persegi panjang dengan batas yang ditentukan oleh gaya goresan saat ini.

strokeRect membutuhkan parameter yang persis sama dengan fillRect: x, y, lebar dan tinggi. Untuk menentukan stroke warnanya, Canvas 2D API milik strokeStyle-nya digunakan. Kita akan membiarkannya pada nilai default hitam.

Sama seperti metode fillRect, warna isian dapat didefinisikan dengan menyetel properti fillStyle.

Perhatikan bahwa kita menambahkan dua piksel pada lebar dan tinggi wadah. Ini untuk benar-benar membuat wadah 50x5 piksel karena Canvas 2D API menempatkan batas di dalam lebar dan tinggi yang ditentukan.

Health bar


Animasi logikanya sudah ditangani oleh metode move yang diwarisi dari objek yang dapat dihitung. Dalam kombinasi dengan warna yang bervariasi, ini akan memberikan perubahan yang bagus untuk persentase kesehatan transisi.

Mengatur Canvas 2D API properti fillStyle sesuai dengan persentase kesehatan sangat sederhana ketika menggunakan beberapa pernyataan if.

Proses menggambar bar kesehatan tidak jauh lebih sulit untuk dilakukan; kita hanya perlu menggambar persegi panjang yang diisi (fillRect) pada posisi yang sama dari wadah, kecuali bahwa kita menambahkan satu piksel untuk lebar dan tinggi untuk menempatkannya di dalam batas-batas wadah.

Lebar bar kesehatan hanya ditemukan dengan mengalikan persentase kesehatan saat ini (value) dengan rasio skala wadah ruang kosong (50) dan jumlah kesehatan maksimum yang mungkin (100). 5 piksel harus cukup sebagai tinggi.

'HP' text

Rendering teks ke kanvas dapat dicapai dengan memanfaatkan metode fillText atau strokeText dari Canvas 2D API. Definisi font dapat diatur dengan properti font (standarnya adalah '10px sans-serif').

Sama seperti persegi panjang, properti fillStyle dan strokeStyle digunakan untuk masing-masing mengatur warna fill atau border. Selain itu, ada juga properti untuk menyetel perataan (textAlign, default ke 'start') dan baseline (textBaseline, default ke 'abjad') teks.

Kita akan menggunakan metode fillText karena kita tidak ingin memiliki batas di sekitar teks. fillText membutuhkan parameter berikut: sepotong teks untuk dicetak dan posisi x dan y.

Untuk menyederhanakan proses menempatkan teks di tempat yang tepat, kita akan menetapkan teks sebagai "top". Masih ada beberapa yang dimasukkan sebelum teks dibuat dan oleh karena itu kita akan mengurangi 3 piksel dari posisi y untuk meletakkannya sejajar dengan bilah kesehatan.


Definisi fungsi akhir

Dan dengan itu, kita telah menyelesaikan objek kesehatan.
Elemen terakhir bagi kita untuk disatukan sebelum kita dapat menyebutnya tujuan adalah objek skor.


Obyek Skor

Objek skor mewarisi dari objek dasar yang dapat dihitung yang, sekali lagi, memberi kita keuntungan memiliki sedikit metode untuk menulis. Ini berarti kita hanya perlu menulis dua metode.

Satu untuk menggambar teks 'PT' (tangan pendek untuk poin) dan value saat ini ke kanvas dan satu untuk mengatur ulang properti objek sehingga pemain akan mulai segar di awal level baru.

Constructor

Karena posisi penghitung skor statis dan tidak perlu diatur ulang pada awal gim baru, tidak masalah untuk menentukannya di konstruktor.

Sedangkan posisi x harus sama dengan bilah kesehatan untuk menyelaraskan interface dengan baik, posisi y harus sedikit lebih rendah. Ini turun menjadi 10 piksel untuk margin atas, 7 piksel tambahan untuk bar kesehatan tingginya dan 5 piksel lainnya untuk margin antara bar kesehatan dan penghitung skor.

Menyetel ulang objek Skor

Metode reset dari objek Score hanya boleh dipanggil pada awal permainan baru karena skor harus diambil bersamaan dengan level yang pemain selesaikan - pengaturan value dan properti targetValue ke nol sudah cukup.

Menggambar objek Skor

Seluruh fase gambar objek skor terdiri dari tidak lebih dari meletakkan dua buah teks di kanvas; 'PT' dan skor saat ini.

Teks 'PT' dapat diposisikan seperti yang dilakukan dengan teks 'HP'; mengubah properti x yang sudah didefinisikan sedikit untuk memposisikannya dengan spasi putih dari penghitung skor yang sebenarnya.

Definisi fungsi akhir

Itu untuk objek skor.
Mari kita lanjutkan ke tahap akhir dan benar-benar menerapkan objek kesehatan dan skor ke dalam game.


Menyatukan Semuanya

Untuk benar-benar mengintegrasikan penghitung kesehatan dan skor ke dalam game, kita harus memperbarui pembungkus fungsi master RGBCatcher.

Dimulai dengan metode run, kita harus menambahkan dua baris untuk itu untuk instantiate objek penghitung skor dan kesehatan baru.

Dalam metode resetGame dan resetLevel, baris yang mengatur variabel kesehatan dan skor menjadi nol, ketika nilai integer masih sederhana, harus diganti dengan panggilan ke kesehatan dan mencetak objek metode reset mereka.

Metode gameLoop rutin untuk menentukan apakah pengguna masih memiliki cukup kesehatan untuk terus bermain, masih bekerja dengan variabel health seolah-olah itu adalah bilangan bulat (health).

Untuk metode gameLoop juga harus ditambahkan panggilan ke health dan skor objek metode update mereka. Ini cocok di bawah panggilan untuk metode update objek basket.

Hal terakhir yang harus kita ubah adalah kenaikan dan penurunan panggilan ke nilai integer kesehatan dan skor lama dalam fungsi checkCollision di bungkus RGBCatcher.

Kedua variabel itu tidak lagi bilangan bulat dan karena itu kita harus menggunakan kesehatan dan objek skor metode change mereka untuk masing-masing menimbulkan kerusakan atau menambah poin ke skor.

Dan kita sudah selesai!


Kesimpulan

Dengan menggunakan akal sehat dan membagi elemen permainan menjadi tugas yang terpisah, tidak terlalu sulit untuk meretas game dasar menggunakan teknologi HTML5.

Jangan ragu untuk terus melanjutkan menjelajahi dunia luar biasa dari Canvas 2D API. Misalnya, Anda dapat mencoba mengubah fase gambar keranjang sehingga sebenarnya ada celah.

Anda juga bisa memikirkan untuk meningkatkan permainan dengan menambahkan blok, yang akan meningkatkan kesehatan pengguna atau menambah skor teratas dengan memanfaatkan fungsionalitas penyimpanan lokal HTML5.

Apa pun yang Anda lakukan, bersenang-senanglah dengan itu!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
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.