Beberapa minggu yang lalu, saya memutuskan untuk mengerjakan game untuk Game Boy, kreasi yang memberi saya kesenangan besar. Nama kerjanya adalah Aqua dan Abu. Game ini memiliki sumber terbuka dan diposting di
GitHub .
Bagaimana ide ini muncul di benak saya
Baru-baru ini saya mendapat pekerjaan magang membuat backend dalam PHP dan Python untuk situs web universitas saya. Ini adalah pekerjaan yang bagus dan menarik, dan saya sangat berterima kasih. Tetapi ... pada saat yang sama, semua kode pengembangan web tingkat tinggi ini telah menginfeksi saya dengan keinginan yang tidak pernah terpuaskan. Dan itu adalah keinginan untuk pekerjaan tingkat rendah dengan bit.
Saya menerima gatal mingguan.io tentang kemacetan permainan dalam surat, yang mengumumkan awal
Mini Jam 4 . Itu adalah 48 jam (well, sebenarnya sedikit lebih besar), di mana batasannya adalah untuk membuat grafik dengan gaya Game Boy. Reaksi logis pertama saya adalah membuat game homebrew untuk Game Boy. Tema kemacetan adalah "musim" dan "nyala".
Setelah berpikir sedikit tentang plot dan mekanisme yang dapat diimplementasikan dalam 48 jam dan sesuai dengan keterbatasan topik, saya datang dengan
klon interpretasi baru tingkat dari permainan SNES 1993 Petualangan Tiny Toon: Buster Busts Loose !, di mana pemain dalam peran Baster memainkan sepakbola Amerika .
Saya selalu suka bagaimana pencipta tingkat ini mengambil olahraga yang sangat kompleks, menyingkirkan semua trik, posisi, dan elemen strategis, sebagai hasil dari mendapatkan permainan yang sangat menarik dan mudah. Jelas, pandangan yang disederhanakan tentang sepak bola Amerika tidak akan menggantikan Madden, seperti halnya NBA Jam (ide serupa: hanya 4 pemain di bidang yang jauh lebih kecil dengan gameplay yang lebih mudah daripada di game biasa) tidak akan menggantikan seri 2K. Tetapi ide ini memiliki daya tarik tertentu, dan angka penjualan NBA Jam mengkonfirmasi hal ini.
Bagaimana semua ini berhubungan dengan ide saya? Saya memutuskan untuk mengambil level sepakbola ini dan membuat ulang sehingga tetap mirip dengan aslinya dan pada saat yang sama segar. Pertama, saya mengurangi permainan menjadi hanya empat pemain - satu bek dan satu penyerang. Ini terutama dilakukan karena keterbatasan perangkat keras, tetapi pada saat yang sama itu akan memungkinkan saya untuk bereksperimen sedikit dengan AI yang lebih cerdas, tidak terbatas pada prinsip "lari ke kiri dan kadang-kadang melompat" dari bermain di SNES.
Demi kesesuaian dengan topik, saya akan mengganti gerbang dengan kolom terbakar, atau dengan api unggun, atau dengan sesuatu seperti itu (saya belum memutuskan), dan bola sepak dengan obor dan ember air. Pemenangnya adalah tim yang mengendalikan kedua api unggun, dan di sekitar konsep sederhana ini Anda dapat dengan mudah membuat plot. Musim juga diperhitungkan: Saya memutuskan bahwa musim akan berubah setiap belokan, sehingga tim pemadam kebakaran mendapat keuntungan di musim panas dan tim pemadam kebakaran di musim dingin. Keuntungan ini terlihat seperti hambatan di lapangan yang hanya mengganggu tim lawan.
Tentu saja, ketika membuat dua tim, dua hewan dibutuhkan yang suka dan tidak suka api. Pada awalnya saya memikirkan semut api dan beberapa serangga air, berdoa belalang dan sejenisnya, tetapi setelah mempelajari masalah ini, saya tidak menemukan serangga yang aktif di musim dingin, jadi saya menggantinya dengan rubah kutub dan tokek. Rubah kutub seperti salju, tokek suka berbaring di matahari, jadi semuanya tampak logis. Pada akhirnya, itu hanya permainan untuk Game Boy.
Selain itu, dalam hal ini masih bisa dimengerti, pada akhir kemacetan permainan itu tidak hampir selesai. Ngomong-ngomong, itu tetap menyenangkan.
Pelatihan Game Boy
Pertama, Anda perlu menentukan persyaratan. Saya memutuskan untuk menulis untuk DMG (nama internal untuk model Game Boy, kependekan dari Dot Matrix Game). Terutama untuk memenuhi persyaratan permainan yang macet, tetapi juga karena saya benar-benar ingin. Secara pribadi, saya belum pernah memiliki game untuk DMG (walaupun ada beberapa game untuk Game Boy Color), tetapi saya menemukan 2-bit estetika menjadi batasan yang sangat bagus dan menarik untuk eksperimen. Mungkin saya akan menambahkan warna tambahan untuk SGB dan CGB, tapi sejauh ini saya belum memikirkannya.
Saya juga memutuskan untuk menggunakan kartrid dengan ROM 32K + tanpa RAM, kalau-kalau saya ingin membuat salinan fisik permainan. CatSkull, yang telah menerbitkan beberapa game Game Boy, seperti Sheep it Up !, Memiliki
kartrid flash 32-kilobyte yang dijual yang sangat cocok untuk saya. Ini adalah batasan tambahan lain, tetapi saya tidak berpikir bahwa dalam waktu dekat saya dapat mengatasi volume 32K dengan permainan yang begitu sederhana. Hal yang paling sulit adalah dengan grafis, dan jika semuanya benar-benar buruk, maka saya akan mencoba untuk mengompresnya.
Sedangkan untuk pekerjaan Game Boy, maka semuanya cukup rumit. Namun, jujur โโsaja, dari semua konsol retro yang harus saya kerjakan, Game Boy adalah yang paling menyenangkan. Saya mulai dengan
tutorial yang sangat baik (setidaknya untuk pertama kalinya, karena tidak pernah selesai) oleh penulis AssemblyDigest. Saya tahu bahwa yang terbaik adalah menulis dalam ASM, betapapun menyakitkannya itu kadang-kadang, karena perangkat kerasnya tidak dirancang untuk C, dan saya tidak yakin bahwa bahasa keren Wiz yang disebutkan dalam tutorial akan cocok untuk jangka panjang. Plus, saya melakukan ini terutama karena
saya dapat bekerja dengan ASM.
Periksa komit 8c0a4eaHal pertama yang harus dilakukan adalah membuat Game Boy untuk boot. Jika logo Nintendo tidak ditemukan pada offset
$104
, dan sisa header tidak dikonfigurasi dengan benar, maka peralatan Game Boy akan menganggap bahwa kartrid dimasukkan dengan tidak benar dan akan menolak untuk memuat. Untuk mengatasi masalah ini sangat sederhana, karena banyak tutorial yang telah ditulis tentang ini.
Inilah cara saya memecahkan masalah tajuk. Tidak ada yang layak mendapat perhatian khusus.
Akan lebih sulit untuk melakukan tindakan yang berarti setelah memuat. Sangat sederhana untuk membuat sistem masuk ke siklus sibuk tanpa batas di mana ia menjalankan satu baris kode berulang-ulang. Eksekusi kode dimulai dengan label
main
(di mana lompatan ke alamat menunjukkan
$100
), jadi Anda perlu memasukkan beberapa kode sederhana di sana. Sebagai contoh:
main: .loop: halt jr .loop
dan itu tidak melakukan apa pun kecuali menunggu interupsi untuk memulai, setelah itu kembali ke label
.loop
. (Selanjutnya, saya akan menghilangkan deskripsi rinci ASM. Jika Anda bingung,
lihat dokumentasi assembler yang saya gunakan .) Anda mungkin ingin tahu mengapa saya tidak kembali ke label
main
. Ini karena saya ingin semuanya sebelum label
.loop
menjadi inisialisasi program, dan semuanya setelah itu terjadi setiap frame. Jadi, saya tidak harus melewati siklus memuat data dari kartrid dan menghapus memori di setiap frame.
Mari kita mengambil satu langkah lagi. Paket assembler RGBDS yang saya gunakan berisi konverter gambar. Karena pada tahap ini saya belum mengambil sumber daya untuk permainan, saya memutuskan untuk menggunakan tombol monokrom dari halaman Tentang saya sebagai bitmap uji. Menggunakan RGBGFX, saya mengonversinya ke format Game Boy dan menggunakan perintah .incbin assembler untuk menyisipkannya setelah fungsi
main
.
Untuk menampilkannya di layar, saya perlu yang berikut:
- LCD mati
- Atur palet
- Setel Posisi Gulir
- Bersihkan Memori Video (VRAM)
- Memuat grafik ubin ke dalam VRAM
- Unduh peta latar belakang ubin VRAM
- Nyalakan kembali LCD
LCD mati
Bagi pemula, ini menjadi kendala paling serius. Pada Game Boy pertama, tidak mungkin hanya menulis data ke VRAM kapan saja. Perlu menunggu saat ketika sistem tidak menarik apa pun. Meniru cahaya fosfor di televisi CRT lama, interval antara setiap frame ketika VRAM terbuka disebut Vertikal-Kosong, atau VBlank (dalam CRT itu adalah dorongan untuk memadamkan sinar kineskop selama pemindaian terbalik). (Ada juga HBlank di antara setiap baris layar, tetapi sangat pendek.) Namun, kita dapat mengatasi masalah ini dengan mematikan layar LCD, yaitu, kita
dapat merekam dalam VRAM tanpa memandang di mana trek fosfor dari layar CRT berada.
Jika Anda bingung, maka
ulasan ini harus menjelaskan banyak hal kepada Anda . Di dalamnya, pertanyaan dianggap dari sudut pandang SNES, jadi jangan lupa bahwa tidak ada berkas elektron, dan angkanya berbeda, tetapi di semua hal lain itu cukup berlaku. Pada dasarnya, kita perlu mengatur bendera FBlank.
Namun, trik Game Boy adalah Anda hanya dapat mematikan LCD selama VBlank. Artinya, kita harus menunggu VBlank. Untuk melakukan ini, gunakan interupsi. Interupsi adalah sinyal bahwa Game Boy mengirim perangkat keras ke CPU. Jika interrupt handler diatur, prosesor berhenti bekerja dan memanggil handler. Game Boy mendukung lima interupsi, dan salah satunya dimulai ketika VBlank dimulai.
Interupsi dapat ditangani dengan dua cara berbeda. Yang pertama dan paling umum adalah tugas
penangan interupsi yang berfungsi seperti yang saya jelaskan di atas. Namun, kami dapat mengaktifkan interupsi tertentu dan menonaktifkan semua penangan dengan mengatur flag aktifkan untuk interupsi ini dan menggunakan opcode
di
. Biasanya tidak melakukan apa-apa, tetapi memiliki efek samping keluar dari HALT opcode, yang menghentikan CPU sebelum terjadi gangguan. (Ini juga terjadi ketika penangan dihidupkan, yang memungkinkan kita untuk keluar dari siklus HALT di
main
.) Jika Anda tertarik, kami juga akan membuat penangan VBlank dari waktu ke waktu, tetapi banyak yang akan tergantung pada nilai-nilai tertentu di alamat tertentu. Karena tidak ada yang diatur dalam RAM sejauh ini, upaya untuk memanggil VBlank handler dapat menyebabkan sistem crash.
Untuk mengatur nilai, kita perlu mengirim perintah ke register perangkat keras Game Boy. Ada alamat memori khusus yang terkait langsung dengan berbagai bagian peralatan, dalam kasus kami, CPU, yang memungkinkan Anda untuk mengubah cara kerjanya. Kami sangat tertarik dengan alamat
$FFFF
(bidang bit interrupt enable),
$FF0F
(bidang bit interrupt yang diaktifkan tetapi tidak tertangani) dan
$FF40
(kontrol LCD). Daftar register ini dapat ditemukan
di halaman yang terkait dengan bagian "Dokumentasi" dari daftar Awesome Game Boy Development.
Untuk mematikan LCD, kita nyalakan VBlank interrupt saja, menetapkan
$FFFF
nilai
$01
, jalankan HALT sampai kondisi
$FF0F == $01
terpenuhi, dan kemudian tetapkan bit 7 dari alamat
$FF40
ke 0.
Mengatur palet dan posisi gulir
Ini mudah dilakukan. Sekarang setelah LCD mati, kita tidak perlu khawatir tentang VBlank. Untuk mengatur posisi pengguliran, cukup untuk mengatur register X dan Y ke 0. Dengan palet, semuanya sedikit lebih rumit. Di Game Boy, Anda dapat menetapkan corak dari grafik pertama ke keempat dari salah satu dari 4 corak abu-abu (atau hijau rawa, jika Anda mau), yang berguna untuk membuat transisi dan sejenisnya. Saya menetapkan gradien sederhana sebagai palet, didefinisikan sebagai daftar bit
%11100100
.
Menghapus VRAM dan memuat grafik ubin
Saat diluncurkan, semua data grafis dan peta latar belakang hanya akan terdiri dari logo Nintendo yang bergulir, yang ditampilkan ketika sistem melakukan booting. Jika saya mengaktifkan sprite (dinonaktifkan secara default), mereka akan menjadi sampah yang tersebar di layar. Anda perlu menghapus memori video untuk memulai dari awal.
Untuk melakukan ini, saya memerlukan fungsi seperti
memset
dari C. (Saya juga membutuhkan
memcpy
analog untuk menyalin data grafik.) Fungsi
memset
mengatur fragmen memori yang ditentukan ke byte tertentu. Ini akan mudah bagi saya untuk mengimplementasikan ini sendiri, tetapi
tutorial AssemblyDigest sudah memiliki fungsi-fungsi ini, jadi saya menggunakannya.
Pada titik ini, saya dapat menghapus VRAM dengan
memset
dengan menulis
$00
(meskipun komit pertama menggunakan nilai
$FF
, yang juga cocok), dan kemudian memuat ubin ubin ke dalam VRAM menggunakan
memcpy
. Lebih khusus lagi, saya perlu menyalinnya ke alamat
$9000
, karena ini ubin yang hanya digunakan untuk grafik latar belakang. (Alamat
$8000-$87FF
hanya digunakan untuk ubin sprite, dan alamat
$8800-$8FFF
umum untuk kedua jenis.)
Pengaturan Peta Ubin
Game Boy memiliki satu lapisan latar belakang, dibagi menjadi 8x8 ubin. Lapisan latar belakang itu sendiri membutuhkan sekitar 32x32 ubin, yaitu, ia memiliki ukuran total 256x256. (Sebagai perbandingan: layar konsol memiliki resolusi 160x144.) Saya perlu secara manual menunjukkan ubin yang membentuk garis gambar saya demi baris. Untungnya, semua ubin disusun secara berurutan, jadi saya hanya perlu mengisi setiap baris dengan nilai dari
N*11
hingga
N*11 + 10
, di mana
N
adalah nomor baris, dan 22 elemen ubin lainnya mengisi
$FF
.
Menghidupkan LCD
Di sini kita tidak perlu menunggu VBlank, karena layar masih tidak akan menyala sampai VBlank, jadi saya hanya menulis ke register kontrol LCD lagi. Saya juga menyertakan lapisan latar belakang dan sprite, dan juga menunjukkan alamat yang benar dari peta ubin dan grafik ubin. Setelah itu saya mendapat hasil sebagai berikut. Saya juga menyalakan interrupt handler lagi menggunakan
ei
opcode.
Pada titik ini, untuk membuatnya lebih menarik, saya menulis interrupt handler yang sangat sederhana untuk VBlank. Dengan menambahkan opcode transisi seharga
$40
, saya dapat membuat fungsi apa pun yang dibutuhkan penangan. Dalam hal ini, saya menulis fungsi sederhana yang menggulung layar ke atas dan ke bawah.
Inilah hasil akhirnya. [Tambahan: Saya baru menyadari bahwa GIF tidak diulang dengan benar, itu harus terus-menerus mentransfer gambar.]
Sejauh ini, tidak ada yang mengejutkan, tetapi secara teori masih keren bahwa saya bisa mendapatkan Warna Game Boy lama saya dan melihat bagaimana kode saya sendiri dieksekusi di atasnya.
Bersenang-senang dengan lembaran kotak-kotak
Untuk menggambar sesuatu di layar, saya secara alami membutuhkan semacam sprite. Setelah mempelajari PPU (Picture Processing Unit) dari konsol Game Boy, saya memutuskan untuk fokus pada sprite 8x8 atau 8x16. Mungkin, saya akan membutuhkan opsi terakhir, tetapi hanya untuk merasakan ukurannya, saya dengan cepat menuliskan screenshot permainan dalam skala 1: 8 pada kertas kotak-kotak.
Saya ingin meninggalkan bagian atas layar di bawah HUD. Menurut saya itu akan terlihat lebih alami daripada dari bawah, karena ketika sudah habis, maka jika karakter perlu untuk sementara memblokir HUD, seperti di Super Mario Bros, mereka dapat melakukannya. Game ini tidak akan memiliki platforming yang kompleks, dan bahkan desain levelnya juga, jadi saya tidak perlu menunjukkan tampilan lapangan yang sangat umum. Posisi karakter di layar dan, mungkin, rintangan yang muncul dari waktu ke waktu akan cukup. Karena itu, saya bisa membeli sprite yang cukup besar.
Jadi, jika satu kotak adalah satu ubin 8x8, maka satu sprite
tidak akan cukup, tidak peduli berapa ukuran yang saya pilih. Ini terutama benar mengingat bahwa hampir tidak akan ada gerakan vertikal dalam game, dengan pengecualian melompat. Jadi saya memutuskan untuk membuat sprite dari empat sprite 8x16. Pengecualian adalah ekor rubah, yang menempati dua spanduk 8x16. Setelah perhitungan sederhana, menjadi jelas bahwa dua rubah dan dua tokek akan menempati 20 dari 40 sprite, artinya, akan dimungkinkan untuk menambahkan lebih banyak sprite tambahan. (Spanduk 8x8 dengan cepat akan keluar dari batas saya, yang saya tidak ingin lakukan pada tahap awal pengembangan.)
Untuk saat ini, saya hanya perlu menggambar sprite. Di bawah ini adalah sketsa kasar pada kertas kotak-kotak. Saya memiliki sprite menunggu, sprite "berpikir" untuk memilih apakah akan lulus atau berlari, seperti dalam permainan SNES ... dan hanya itu. Saya juga berencana untuk membuat sprite karakter berjalan, karakter melompat dan karakter yang lawan ambil. Tapi sebagai permulaan, saya menggambar hanya menunggu dan berpikir sprite, agar tidak menyulitkan. Saya masih tidak melakukan sisanya, saya perlu melakukan ini.
Ya, saya tahu, saya tidak menggambar dengan baik. Perspektif adalah hal yang sulit. (Ya, dan wajah rubah kutub ini mengerikan.) Tapi itu sangat cocok untukku. Desain karakter tidak memiliki fitur khusus, tetapi cocok untuk permainan yang macet. Tentu saja, saya menggunakan tokek dan rubah kutub asli sebagai referensi. Apakah itu tidak terlihat?
Anda tidak bisa mengatakannya. (Sebagai catatan: baru saja melihat foto-foto ini lagi, saya menyadari bahwa ada perbedaan besar antara tokek dan kadal. Saya tidak tahu apa yang harus dilakukan dengan ini, kecuali menganggap saya bodoh ...) Saya pikir Anda dapat menebak bahwa sumber inspirasi untuk Blaze the Cat dari seri game Sonic menjadi kepala rubah.
Awalnya, saya ingin para pembela dan pemain depan dalam setiap tim memiliki jenis kelamin yang berbeda dan lebih mudah untuk membedakan di antara mereka. (Saya juga akan membiarkan para pemain memilih jenis kelamin karakter mereka.) Namun, ini akan membutuhkan lebih banyak gambar. Jadi saya memilih tokek jantan dan rubah betina.
Dan akhirnya, saya menggambar splash screen karena ada tempat untuk itu di selembar kertas kotak-kotak.
Ya, pose aksi masih jauh dari ideal. Rubah kutub harus lebih kesal dan lari, dan tokek harus terlihat mengancam. Defender Fox di latar belakang - referensi menyenangkan untuk seni di kotak Doom.
Digitalisasi sprite
Kemudian saya mulai mengubah gambar kertas menjadi sprite. Untuk ini, saya menggunakan program GraphicsGale, yang baru-baru ini dibuat gratis. (Saya tahu Anda bisa menggunakan asesprite, tapi saya lebih suka GraphicsGale.) Bekerja pada sprite ternyata jauh lebih rumit dari yang saya harapkan. Masing-masing kotak dari sprite yang ditunjukkan di atas membutuhkan hingga 4 piksel dalam kisi 2x2. Dan kotak ini sering memiliki JAUH lebih detail dari 4 piksel. Karena itu, saya harus menyingkirkan banyak detail sketsa. Kadang-kadang bahkan sulit untuk mematuhi bentuk yang sederhana, karena itu perlu untuk meninggalkan tempat yang dapat diterima oleh mata atau hidung. Tapi menurut saya semuanya terlihat baik, bahkan jika sprite menjadi sangat berbeda.

Mata rubah kehilangan bentuk almond dan berubah menjadi garis setinggi dua piksel. Mata tokek mempertahankan kebulatannya. Kepala tokek harus diperbesar, menyingkirkan pundak yang lebar, dan semua tikungan yang bisa dimiliki rubah secara signifikan dihaluskan. Tapi jujur, semua perubahan mudah ini tidak terlalu buruk. Kadang-kadang saya sulit memilih variasi mana yang lebih baik.
GraphicsGale juga memiliki fungsi yang mudah digunakan untuk lapisan dan animasi. Ini berarti bahwa saya dapat menghidupkan ekor rubah secara terpisah dari tubuhnya. Ini sangat membantu untuk menghemat ruang VRAM yang berharga karena saya tidak perlu menduplikasi ekor di setiap bingkai. Selain itu, ini berarti Anda bisa mengibas-ngibaskan ekor Anda dengan kecepatan variabel, melambat ketika karakter berdiri, dan mempercepat saat berlari. Namun, ini membuat pemrograman sedikit lebih rumit. Tapi saya tetap akan mengambil tugas ini. Saya memilih 4 frame animasi, karena ini sudah cukup.
Anda mungkin memperhatikan bahwa rubah kutub menggunakan tiga warna abu-abu paling terang, sedangkan tokek menggunakan tiga warna abu-abu paling gelap. Pada GameBoy, ini dapat diterima, karena meskipun hanya ada tiga warna dalam sprite, konsol memungkinkan Anda menentukan dua palet. Saya membuatnya sehingga palet 0 digunakan untuk rubah, dan palet 1 digunakan untuk tokek. Itu semua set palet yang tersedia sudah berakhir, tetapi saya tidak berpikir saya membutuhkan yang lain.
Saya juga harus menjaga latar belakang. Saya tidak peduli dengan sketsa-sketsanya, karena saya merencanakan bahwa itu akan menjadi warna solid atau pola geometris sederhana. Saya belum mendigitalkan screen saver, karena saya tidak punya cukup waktu.
Memuat sprite ke dalam game
Periksa dengan komitmen
be99d97 .
Setelah masing-masing bingkai grafis karakter disimpan, dimungkinkan untuk mulai mengonversinya ke format GameBoy. Ternyata di RGBDS ada utilitas yang sangat nyaman untuk ini yang disebut RGBGFX. Anda dapat memanggilnya dengan perintah
rgbgfx -h -o output.bin input.png
dan itu akan membuat satu set ubin yang kompatibel dengan GameBoy. (Sakelar -h menentukan mode ubin yang kompatibel dengan 8x16 sehingga konversi dilakukan dari atas ke bawah, dan bukan dari kiri ke kanan.) Namun, itu tidak memberikan binding dan tidak dapat melacak ubin duplikat ketika setiap frame adalah gambar yang terpisah. Tapi kami akan meninggalkan masalah ini nanti.
Setelah menghasilkan file .bin keluaran, cukup tambahkan di assembler menggunakan
incbin "output.bin"
. Untuk menyatukan semuanya, saya membuat file umum "gfxinclude.z80", yang berisi semua grafik yang akan ditambahkan.
Namun, sangat membosankan untuk membuat ulang grafik secara manual setiap kali sesuatu berubah. Jadi saya mengedit file build.bat, menambahkan baris
for %%f in (gfx/*.png) do rgbds\rgbgfx -h -o gfx/bin/%%f.bin gfx/%%f
, yang mengubah setiap file. png di folder gfx / ke file bin dan menyimpannya ke gfx / bin. Ini sangat menyederhanakan hidup saya.
Untuk membuat grafik latar belakang, saya menggunakan cara yang
jauh lebih malas. RGBASM memiliki arahan
dw `
. Ini diikuti oleh garis 8 nilai dari 0 hingga 4 sama dengan satu baris data piksel. Karena sprite latar sangat sederhana, ternyata lebih mudah untuk menyalin dan menempelkan pola geometris sederhana untuk membuat pola yang solid, bergaris atau kotak-kotak. Di sini, misalnya, terlihat seperti ubin tanah.
bg_dirt: dw `00110011 dw `00000000 dw `01100110 dw `00000000 dw `11001100 dw `00000000 dw `10011001 dw `00000000
Dia menciptakan serangkaian garis bergeser dengan ilusi perspektif. Ini adalah pendekatan yang sederhana namun cerdas. Dengan rumput itu sedikit lebih rumit. Awalnya, itu adalah sekelompok garis horizontal 2 piksel tinggi, tetapi saya secara manual menambahkan beberapa piksel yang menambahkan sedikit noise yang membuat rumput terlihat lebih baik:
bg_grass: dw `12121112 dw `12121212 dw `22112211 dw `11121212 dw `22112211 dw `21212121 dw `12121212 dw `12211222
Render gambar
Di GameBoy, sprite disimpan di area yang disebut OAM, atau Object Attribute Memory. Ini hanya berisi atribut (arah, palet dan prioritas), serta nomor ubin.
Cukup bagi saya untuk mengisi area memori ini untuk menampilkan sprite di layar.Meski ada fitur kecil. Pertama, Anda perlu memuat gambar dari ROM ke VRAM. GameBoy hanya dapat membuat ubin yang disimpan di area khusus memori yang disebut VRAM. Untungnya, untuk menyalin dari ROM ke VRAM, itu sudah cukup untuk melakukannya memcpy
pada tahap inisialisasi program. Ternyata dengan hanya 6 sprite karakter dan 4 ubin ekor, saya sudah mengambil seperempat area VRAM yang dialokasikan untuk sprite. (VRAM biasanya dibagi menjadi area latar belakang dan sprite, dan 128 byte adalah umum untuk mereka.)Selain itu, akses ke OAM hanya dimungkinkan selama VBlank. Saya mulai dengan mengatakan bahwa VBlank sedang menunggu perhitungan sprite, tetapi saya mengalami masalah karena perhitungan sprite berlangsung sepanjang waktu yang dialokasikan oleh VBlank dan tidak mungkin untuk menyelesaikannya. Solusi di sini adalah menulis ke area memori terpisah di luar VBlank dan cukup menyalinnya ke OAM selama VBlank.Ternyata, GameBoy memiliki prosedur penyalinan perangkat keras khusus, semacam DMA (Akses Memori Langsung, akses langsung ke memori) yang melakukan hal itu. Dengan menulis ke register tertentu dan pergi ke siklus sibuk di HiRAM (karena ROM tidak tersedia selama DMA), Anda dapat menyalin data dari RAM ke OAM lebih cepat daripada menggunakan fungsimemcpy
. Jika tertarik, maka detail menarik bisa ditemukan di sini .Pada tahap ini, saya hanya bisa membuat prosedur yang menentukan apa yang nantinya akan ditulis ke DMA. Untuk melakukan ini, saya perlu menyimpan keadaan objek di tempat lain. Minimal, hal-hal berikut diperlukan:- Ketik (tokek, rubah kutub atau membawa barang dari salah satu tim)
- Arahan
- Posisi X
- Posisi Y
- Bingkai animasi
- Timer animasi
Dalam keputusan pertama, sangat berantakan, saya memeriksa jenis objek, dan bergantung padanya, saya beralih ke prosedur yang secara spritically menggambar objek jenis ini. Prosedur rubah kutub, misalnya, mengambil posisi dalam X, tergantung pada arahnya, ditambahkan atau dikurangi 16, menambahkan dua sprite ekor, dan kemudian bergerak naik turun sprite utama.Berikut adalah tangkapan layar tentang bagaimana sprite terlihat di VRAM saat merender di layar. Bagian kiri adalah sprite individu, angka heksadesimal di sebelahnya, dari atas ke bawah - posisi vertikal dan horizontal, ubin dan bendera atribut. Di sebelah kanan Anda dapat melihat bagaimana semuanya terlihat setelah perakitan..
and
%11
. VRAM 4 * ( 4 ), 4 , VRAM. ( ),
, .
, ,
,
and
dan derajat dua yang dipilih oleh saya adalah 0, kenaikan timer objek dilakukan. Dengan demikian, setiap objek individu dapat menghitung mundur penghitung waktu animasi pada kecepatan yang diperlukan. Ini bekerja dengan sempurna dan memungkinkan saya untuk memperlambat ekor ke tingkat yang masuk akal.Kesulitan
Tetapi jika semuanya begitu sederhana. Jangan lupa bahwa saya berhasil semua ini dalam kode, menggunakan subprocedure saya sendiri untuk setiap objek, dan jika Anda harus melanjutkan, Anda perlu melakukan ini di setiap frame. Saya harus menentukan cara melanjutkan ke sprite berikutnya, serta ubin apa itu terdiri dari, memanipulasi register secara manual.Itu adalah sistem yang sama sekali tidak stabil. Untuk menggambar satu frame, perlu untuk menyulap sejumlah besar register dan waktu CPU. Nyaris mustahil untuk menambahkan dukungan untuk personel lain, dan bahkan jika saya berhasil, dukungan sistem akan sangat menyakitkan. Percayalah, itu benar-benar kekacauan.Saya membutuhkan sistem di mana kode untuk rendering sprite akan digeneralisasikan dan langsung, sehingga tidak akan menjalin kondisi, manipulasi register dan operator matematika.Bagaimana saya memperbaikinya? Saya akan membicarakan hal ini di bagian artikel selanjutnya.