Secara keseluruhan
Tutorial ini akan memberikan petunjuk kepada Anda, bagaimana cara membuat game dengan menggunakan Godot. Anda akan mempelajari bagaimana cara kerja editor pada Godot, bagaimana membuat struktur sebuah project, dan bagaimana cara membuat game 2D dengan Godot.
Catatan:
Project ini adalah pengenalan terhadap Godot Engine. Mengasumsikan bahwa Anda memiliki kemampuan dalam pengalaman pemrograman. Jika Anda belum mengenal pemrograman secara keseluruhan, Saya harap agar membaca artikel sebelumnya tentang: Scripting (Penulisan Scirpt).Dodge the Creeps |
Pengaturan project
Jalankan Godot dan buat satu project baru. Kemudian, download file berikut: ⏬dodge_assets.zip - berisi gambar, font dan suara yang dibutuhkan kedalam game. Ekstrak ke dalam folder project.
Catatan:
untuk tutorial ini, kita asumsikan Anda telah familiar dengan editor Godot. Jika anda belum pernah tahu sebelumnya tentang Scene dan Nodes, Saya sarankan untuk membacanya terlebih dahulu guna mempermudah Anda untuk memahami konsep pengaturan project.
Game ini akan menggunakan mode portrait, jadi kita butuh untuk mengatur luas jendela dari game. Klik (Menu Utama) Project -> Project Settings -> Display -> Window dan jadikan properti "Width" ke 480 dan "Height" ke 720.
Mengorganisasi project
Dalam project ini, kita akan membuat 3 scene independen, yaitu adalah: Player, Mob, dan HUD, dimana kita akan menggabungkannya di dalam satu scene utama yang adalah scene Main. Dalam sebuah project yang besar, sangat berguna apabila Anda membuat folder spesifik, yang hanya menyimpan suatu bagian scene dan script (misla folder enemies, yang berarti terdapat scene dan script yang berhubungan dengan musuh dalam game). Tetapi dalam game yang relatif kecil seperti ini, Anda bisa menyimpan file scene dan script di root folder, yang adalah res://. Anda bisa melihat folder project Anda di tab FileSystem di bagian kiri atas editor:
FileSystem |
Scene player
Yang pertama akan kita buat adalah object pada scene Player. Salah satu kelebihan dari membuat player secara terpisah adalah kita dapat melakukan tes padanya secara terpisah, meski sebelum kita membuat bagian lain dari game sekalipun.
Struktur nodenya
Untuk memulai, klik tombol "Add/Create a New Node" dan tambahkan node Area2D ke scene.
Menambahkan node |
Dengan menggunakan Area2D kita bisa mendeteksi object yang menumpang tindih (overlap) terhadap object player. Rubah namanya menjadi Player dengan melakukan klik nama node-nya. Node ini merupakan node utama scene Player. Kita bisa menambahkan node lain kedalamnya untuk (dengan kata lain) menambahkan fungsinya.
Sebelum kita menambah node anakan terhadap node Player, kita ingin memastikan bahwa kita tidak secara sengaja mengubah ukurannya dan/atau memindah posisinya. Maka dari itu silahkan pilih dan klik sekali lagi pada node player lalu pada toolbar silahkan klik ikon yang seperti terlihat pada gambar dibawah ini:
Simpan scene. klik Scene -> Save, atau tekan Ctrl+S jika di Windows/Linux atau Cmd+S pada Mac.
Tooltip "Makes sure the object's children are not selectable (Pastikan object pada node anakan tidak dapat dipilih)" |
Catatan:
untuk project ini, kita akan mengikuti tata cara (kebiasaan) penamaan di Godot. Seperti apabila Classes (Node) kita namai dengan PascalCase/UpperCamelCase, variables (variabel) kita namai dengan menggunakan snake_case, dan constants (konstanta) kita namai dengan mengguanakan ALL_CAPS.
Sprite Animasi
Klik pada node Player dan tambahkan node AnimatedSprite sebagai anakannya. AnimatedSprite akan menangani semua penampilan dan animasi dari karakter player kita. Perhatikan ada simbol peringatan muncul disamping nama node. Sebuah AnimatedSprite membutuhkan SpriteFrames, yang merupakan daftar dari animasi yang akan ditampilkan. Untuk membuatnya, cari properti Frames pada inspector dan klik "<null>" -> "New SpriteFrames". Kemudian, di lokasi yang sama, klik <SpriteFrames> untuk membuka panel "SpriteFrames":
Di bagian sebelah kiri adalah daftar nama animasi. Klik pada bagian tulisan "default" dan ganti namanya menjadi "right". Kemudian klik tombol "Add" pada pojok kiri atas untuk membuat grup animasi baru, namai dengan "up". Geret (drag) dua gambar untuk tiap animasi dari FileSystem yang bernama playerGrey_up[1/2] dan playerGrey_walk[1/2], kedalam bagian "Animation Frames" pada panel:
Gambar player sepertinya terlalu besar untuk jendela tampilan game, maka kita butuh mengecilkan ukurannya. Klik node AnimatedSprite dan atur properti Scale pada inspector, rubah propertinya menjadi (0.5, 0.5). Anda bisa menemukan properti tersebut pada bagian Node2D:
Yang terakhir, tambahkan node CollisionShape2D sebagai anakan dari node Player. Node ini adalah sebagai penentu "hitbox" atau bisa dibilang sebagai penentu area pemicur dari karakter player. Untuk karakter ini, kita akan membuat CapsuleShape2D karena bentuknya yang paling cocok terhadap animasinya. Untuk itu selanjutnya, klik pada bagian samping dari properti "Shape" di inspector, klik "<null>" -> "New CapsuleShape2D". Kemudian Atur besarnya, sesuaikan dengan gambar:
Panel SpriteFrames |
Menambahkan animasi |
Scale |
Atur ukuran shape |
Peringatan:
Jangan menggunakan titik luar (yang memiliki garis) untuk mengubah skala dari object CollishionShape2D! Pastikan Anda menggunakan titik yang dilingkari merah pada gambar di atas sebagai pengatur ukuran (skala). Karena apabila Anda mengatur ukuran menggunakan skala luaran dari object ini, akan berakibat tidak terdeteksinya perubahan skala/ukuran pada object shape tersebut, yang akhirnya memunculkan Error pada sistem debugger Godot atau bahkan membuat game Anda crash saat dijalankan.
Ketika semua langkah diatas sudah dijalankna, maka node Player dalam scene akan terlihat seperti gambar dibawah ini:
Scene Player |
Menggerakkan karakter player
Sekarang kita butuh untuk menambahkan fungsi tambahan yang tidak bisa kita dapatkan dari kemampuan sebuah node secara bawaan, jadi perlu ditambahkan script untuk hal ini. Klik node Player dan klik tombol "Add Script":
Di dalam jendela pengaturan script, langsung saja klik tombol "Create":
Tombol add script |
Catatan:
Jika Anda membuat script menggunakan bahasa pemrograman C#, pilih opsi sesuai dengan bahasa yang diguanakan pada pilihan Language sebelum menekan tombol "Create".Jendela pengaturan script |
Catatan:
Jika Anda belum pernah tahu tentang GDScript sebelumnya, Saya sarankan untuk membaca artikel sebelumnya tentan Penulisan Script sebelum melanjutkan ke tahap ini.extends Area2D export (int) var speed # How fast the player will move (pixels/sec). var screensize # Size of the game window.Menggunakan keyword export sebelum variabel speed adalah bertujuan untuk memungkinkan kita agar dapat mengubah nilai variabel tersebut melalui Inspector. Cara ini mempermudah kita agar lebih cepat mengakses properti suatu node, dengan kata lain memberikan kita kemampuan untuk membuat properti secara manual kepada suatu object. Klik pada node Player dan atur speed-nya menjadi 400.
Hasil dari metode export variable |
func _ready(): screensize = get_viewport_rect().size
Sekarang kita akan menggunakan fungsi _process() untuk menentukan apa yang karakter (player) akan lakukan. _process() akan dipanggil setiap frame, jadi kita akan menggunakannya sebagai elemen update (pembaruan) pada game kita, disini akan kita gunakan sebagai:
- Memeriksa input (dalam hal ini input yang dilakukan pemain game).
- Menggerakkan sesuai dengan arah yang telah ditentukan.
- Memainkan animasi yang sesuai.
Pertama, kita perlu melakukan pemeriksaan terhadap input (masukan) - apakah pemain menekan tombol keyboard? Untuk game ini, kita memiliki 4 arah input yang harus di cek. Peta input sudah ditentukan pada Project Settings dibawah opsi "Input Map". Anda bisa menentukan sendiri event khusus lalu membuatkannya tombol sendiri, input dari mouse, atau input lain kepada event tersebut. Untuk tutorial ini kita akan menggunakan default event yang telah ditentukan sebelumnya yaitu menggunakan tombol panah pada keyboard.
Anda bisa mendeteksi tombol mana yang ditekan dengan menggunakan metode Input.is_action_pressed(), dimana akan menghasilkan nilai true apabila tombol ditekan atau false apabila tidak ada penekanan pada tombol yang dimaksud.
func _process(delta): var velocity = Vector2() # The player's movement vector. if Input.is_action_pressed("ui_right"): velocity.x += 1 if Input.is_action_pressed("ui_left"): velocity.x -= 1 if Input.is_action_pressed("ui_down"): velocity.y += 1 if Input.is_action_pressed("ui_up"): velocity.y -= 1 if velocity.length() > 0: velocity = velocity.normalized() * speed $AnimatedSprite.play() else: $AnimatedSprite.stop()
Kita lakukan cek setiap input dan melakukan penambahan dari nilai velocity untuk mendapatkan sebuah arah total. Sebagai contoh, jika Anda menekan tombol right dan down pada saat bersamaan, maka hasilnya adalah vector velocity bernilai (1, 1). Dalam kasus ini, apabila kita melakukan penambahan pada pergerakan horizontal dan vertical, maka node player akan bergerak lebih cepat daripada jika node tersebut hanya bergerak secara horizontal saja.
Kita bisa mengatasi hal tersebut menggunakan metode normalize yang diaplikasikan pada velocity-nya, yang berarti kita menjadikan "panjang" velocity selalu bernilai 1, dan mengalikannya dengan speed (kecepatan) yang diinginkan. Dengan begini tidak akan ada penambahan kecepatan padasaat bergerak secara diagonal.
Kita bisa mengatasi hal tersebut menggunakan metode normalize yang diaplikasikan pada velocity-nya, yang berarti kita menjadikan "panjang" velocity selalu bernilai 1, dan mengalikannya dengan speed (kecepatan) yang diinginkan. Dengan begini tidak akan ada penambahan kecepatan padasaat bergerak secara diagonal.
Tips
Jika Anda belum pernah mengetahui perhitungan vector matematik sebelumnya, atau hanya sekedar ingin mengingat kembali, Anda bisa membaca penjelasan tentang penggunaan vector di Godot pada artikel berikut Vector Math. Hanya sebagai referensi saja, belum terlalu dibutuhkan dalam tutorial ini.Tips
$ merupakan simbol yang bernilai sebuah path relatif terhadap node dimana script dipasang, dan akan bernilai null jika tidak ditemukan node. Karena AnimatedSprite adalah node anakan dari node dimana script dipasang, maka kita bisa menggunakan $AnimatedSprite untuk memanggilnya.$ adalah code singkat pengganti get_node(). Jadi code diatas yang adalah $AnimatedSprite.play() berarti sama dengan get_node("AnimatedSprite").play()
position += velocity * delta position.x = clamp(position.x, 0, screensize.x) position.y = clamp(position.y, 0, screensize.y)
Tips
Clamping (menjepit) sebuah metode yang berfungsi untuk membatasi suatu nilai, berarti membatasinya sesuai batas yang ditentukan. Dari script diatas bisa kita simpulkan bahwa position.x dan position.y dibatasi mulai dari 0 hingga maksimal seluas ukuran layar.Peringatan
Apabila Anda mendapati error yang muncul pada panel "Debugger" yang mengacu pada "null instance", hal ini lebih kepada kesalahan Anda dalam mengeja nama node yang dipanggil dalam script. Penamaan node adalah sesuatu yang case-sensitive berarti harus diperhatikan penggunaan tiap hurufnya, jadi $NodeName atau get_node("NodeName") harus benar-benar (secara pengejaan dan besar/kecil hurufnya) sama dengan yang ada di scene tree.Pemilihan animasi
Sekarang node player bisa bergerak, kita butuh menentukan animasi mana yang AnimationSprite akan mainkan sesuai dengan arah dari node bergerak. Kita memiliki animasi "right" (kanan), yang tentunya harus dibalik agar sesuai jika node bergerak ke "left" (kiri), untuk itu kita gunakan metode flip_h yang berarti membalik secara horizontal (flipped horizontally). Sedangkan untuk animasi "up", agar kita memiliki animasi "down" (bawah), maka harus dibalik menggunakan flip_v (flipped_vertically). Mari kita tanamkan code ini di paling bawah dari fungsi _process():
if velocity.x != 0: $AnimatedSprite.animation = "right" $AnimatedSprite.flip_v = false $AnimatedSprite.flip_h = velocity.x < 0 elif velocity.y != 0: $AnimatedSprite.animation = "up" $AnimatedSprite.flip_v = velocity.y > 0
Tekan Play Scene sekali lagi dan pastikan bahwa animasinya sudah benar sesuai dengan arah pergerakan player. Ketika Anda sudah yakin semuanya berjalan dengan baik, tambahkan code dibawah ini kedalam fungsi _ready(), untuk menyembunyikan player saat awal game dijalankan:
hide()
Mempersiapkan hambatan (collisions)
Kita ingin Player untuk mendeteksi ketika sedang bertabrakan dengan musuh, tapi kita belum membuat satu musuh sekalipun. Bukan suatu masalah, karena kita akan menggunakan fungsi signal dari Godot untuk membuatnya bekerja.
Tambahkan code berikut ini di dalam scritp, taruh dibawah code extends Area2d:
signal hit
Code diatas merupakan metode untuk membuat sebuah custom signal yang diberi nama "hit", yang dimana akan dipancarkan oleh node player ketika nantinya berbenturan dengan node enemy (musuh). Kita akan menggunakan Area2D untuk mendeteksi rintangan. Pilih node Player dan klik pada tab "Node" (disamping tab Inspector) untuk melihat list signal yang bisa dipancarkan oleh node player:
Perhatikan pada signal buatan kita sendiri yaitu signal "hit" yang muncul juga pada kumpulan signal node ini. Karena nantinya kita akan membuat enemy menggunakan node RigidBody2D, maka akan kita gunakan signal body_entered( Object body ) yang terdapat pada Area2D; signal ini akan memancar ketika sebuah object body memasuki Area2D (dalam hal ini adalah player). Untuk itu klik signal tersebut, lalu klik "Connect.." dan "Connect" lagi di jendela "Connecting Signal", kita tidak perlu mengganti pengaturan apapun yang ada dalam jendela tersebut. Selanjutnya Godot akan secara otomatis membuat satu fungsi baru yaitu _on_Player_body_entered di dalam script.
Setelah itu tambahkan code dibawah ini pada fungsi signal:
Signal yang (mungkin) dipancarkan oleh node player |
Tips
Ketika melakukan koneksi signal, Anda bisa membuat sendiri nama fungsi yang digunakan dalam penyambungan signal ke node, dengan cara mengganti nama fungsinya pada kolom "Method in Node".Setelah itu tambahkan code dibawah ini pada fungsi signal:
func _on_Player_body_entered(body): hide() # Player disappears after being hit. emit_signal("hit") $CollisionShape2D.disabled = true
Catatan:
Menonaktifkan (disabling) collision shape dari area berarti membuatnya tidak bisa mendeteksi node lain yang menabraknya. Dengan mematikan fungsi tersebut, berarti memastikan agar signal tidak terpicu (memancar) lebih dari satu kali.Bagian terakhir dalam scene player adalah membuat fungsi untuk mereset ulang Player pada saat awal game diload/dimainkan.
Sampai disini Anda telah menguasai beberapa poin yang merupakan fundamental dalam membuat sebuah game menggunakan Godot. Untuk part selanjutnya akan membahas tentang membuat scene enemy (musuh). Bersambung...
0 komentar:
Posting Komentar