Selasa, 30 Oktober 2018

Membuat Game - Part 1

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.
Game ini diberi nama "Dodge the Creeps!" (mengindari monster). Karakter Anda harus sebisa mungkin bergerak dan menghindari musuh, semakin lama semakin tinggi pula skor yang akan didapat. Berikut ini adalah contoh jadinya:
Dodge the Creeps
Dodge the Creeps
Kenapa 2D? karena Game 3D lebih kompleks dari pada game 2D. Anda harus memulai dari 2D hingga benar-benar memahami proses dalam pengembangan sebuah game.

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.
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
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
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:
Tooltip "Makes sure the object's children are not selectable (Pastikan object pada node anakan tidak dapat dipilih)"
Simpan scene. klik Scene -> Save, atau tekan Ctrl+S jika di Windows/Linux atau Cmd+S pada Mac.

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":
Panel SpriteFrames
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:
Menambahkan animasi
Menambahkan animasi
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:
Scale
Scale
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:
Atur ukuran shape
Atur ukuran shape

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":
Tombol add script
Tombol add script
Di dalam jendela pengaturan script, langsung saja klik tombol "Create":
Jendela pengaturan script
Jendela pengaturan script
Dimulai dengan membuat member dari variabel yang dibutuhkan oleh object:
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
Hasil dari metode export variable
Fungsi _ready() akan dipanggil pada saat awal node memasuki scene tree, dimana merupakan waktu yang tepat untuk mendapatkan ukuran dari jendela game:
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 juga melakukan cek terhadap pergerakan player, dengan begitu kita bisa mengatur animasinya, dimana saat animasi berhenti, dimana saat animasi dimulai.
Sekarang kita memiliki arah bergerak, kita bisa mengubah posisi Player dan tambahkan metode clamp() ke dalam fungsi _process agar menahan node player selalu berada didalam layar game.
position += velocity * delta
position.x = clamp(position.x, 0, screensize.x)
position.y = clamp(position.y, 0, screensize.y)
Klik "Play Scene" (F6) dan pastikan Anda bisa menggerakkan player ke arah manapun.

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:
Signal yang (mungkin) dipancarkan oleh node player
Signal yang (mungkin) 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:
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