Ohayoouu, developeru-tachi, gengki desuka?
Melanjutkan dari tulisan Berkenalan dengan Love2D. Kali ini saya akan membuat Nyo-nyo bisa berjalan dengan input keyboard, oia kalau kimi-tachi belum baca bagian sebelumnya, boleh dibaca dahulu bagian itu -- cukup bagian yang sistem koordinat, menampilkan gambar dan laifsaikel saja.
Flashback dan Refactor
Kemarin kodingan kita seperti ini:
function love.load()
nyoNyo = love.graphics.newImage("nyo-nyo.png")
end
function love.draw()
love.graphics.draw(nyoNyo, 0,0)
love.graphics.print("Nyo Nyo", 0,49)
end
sekarang kita rubah menjadi sepert ini:
function love.load()
nyo = {}
nyo.image = love.graphics.newImage("nyo-nyo.png")
nyo.pos_x = 10
nyo.pos_y = 10
nyo.speed = 10
end
function love.draw()
love.graphics.draw(nyo.image, nyo.pos_x,nyo.pos_y)
end
Penjelasan:
-
nyo = {}
adalah data berbentuk table, map atau pasangan key-value, mirip JSON la. -
nyo.image = love....("nyo-nyo.png")
, kita membuat key bernamaimage
dengan datalove.graphics.newImage("nyo-nyo.png")
. - Pendekatan ini membungkus attribut yang berkaitan dengan nyoNyo seperti gambar, posisi x dan y, kecepatan supaya lebih terorganisir agar interaksi lebih mudah. Pikir aja kaya objek di oop.
- Table
nyo
ini akan sering di pakai saat draw dan update, basically table ini untuk mewakili keberadaan objeknyo
dalam muncul window dan menerima interaksi saat proses lifesaikel.
Baca Input dari Kibot
Cara kita tau kalau tombol kibot sedang ditekan dapat menggunakan fungsi love.keyboard.isDown(<key>)
dengan paramater key
yang berarti karakter yang dipencet keak esc
, a
, b
dkk.
Saat tombol karakter dipencet, fungsi ini akan mengembalikan nilai true
dan sebaliknya. Misalnya love.keyboard.isDown("space")
ketika kita menekan ataupun menahan tombol spasi ia akan mengembalikan true
saat dipanggil.
Perhatikan kode berikut:
function love.update(dt)
-- fokus sumbu X
if love.keyboard.isDown("left") then
nyo.pos_x = nyo.pos_x - nyo.speed
elseif love.keyboard.isDown("right") then
nyo.pos_x = nyo.pos_x + nyo.speed
-- fokus sumbu Y
elseif love.keyboard.isDown("up") then
nyo.pos_y = nyoo.pos_y - nyo.speed
elseif love.keyboard.isDown("down") then
nyo.pos_y = nyo.pos_y + nyo.speed
end
end
Penjelasaan:
- Disini kita menggunakan laifsaikel
love.update
fungsi ini akan dipanggil sebanyak jumlah render frame perdetik (FPS), commonly 30 FPS. Ini kenapa kalo FPS drop game menjadi lambat karena rate rendering dan updatingnya menjadi menjadi kecil, keuntungan FPS tinggi (let's say 60) punya gambar dan interaksi yang halus tapiresource hungry
karena perform lebih sering. - Alasan kenapa pakai
love.update
ketimbanglove.keypressed
karena perlu interaksi yang kontinuos supaya animasinya jalan, keypressed dia sifatnya di ketik (diskrit) karena ke trigger ketika tombol di pencet (IsPress
) bukan ditekan (IsDown
). -
nyo.speed
, ini menyimpan kecepatan gerak gambar Nyo berdasarkan jarak piskelnya. -
love.keyboard.isDown("left")
ini kita mendeteksi apakah kibot simbol panah kiri ditekan, jika ditekan ke kiri akan mengurangi piksel sebanyak 10, kenapa ke kiri di kurang ? liat gambar babi tentang sistem kordinat di tulisan sebelumnya. -
love.keyboard.isDown("up")
sama seperti diatas, hanya bedanya mengetahui untuk gambar bergerak ke atas. Kenapa sumbu Y dikurang alasanya sama, sebab titik teratas adalah 0 jadi mendekati 0 berarti bergerak keatas, kalau kebawah menjauh titik teratas yakni 0 jadi ditambah. - sisanya begitu.
Kekurangan dari kode ini tidak bisa menerima input simultan (kibot dipencet barengan), tapi tidak masalah, kita masih bisa bikin game walaupun pencetanya ga simultan.
Bagi yang belum tau pergerakan seperti ini namanya top-down
alias atas bawah kiri kanan, game yang kayak gini contohnya Harvest Moon series versi GBA.
Attaching Debugger
Supaya kita ga meramal apalagi sampai main dukun dan pelet. Kita tambahkan sedikit informasi tentang posisi Nyo-Nyo, di pojok kiri atas.
function love.draw()
love.graphics.draw(nyo.image, nyo.pos_x,nyo.pos_y)
-- tambahin ini
love.graphics.print("posisi Nyo-Nyo, x: ".. nyoNyo.pos_x .." y: ".. nyoNyo.pos_y, 0, 0)
end
Hasilnya kayak gini:
Nyo-nyo nembus Window
Melihat karakter yang ngilang nembus window itu berasa horor, tau-tau udah di folder C:\Windows\system32 aja xixixi. Untuk mengatasi ini kita perlu melakukan clamping, jadi ketika input masuk dan posisi karakter sudah melebih luas window maka tidak melakukan perhitungan lagi.
Karena posisi gerak dibatasi oleh sumbu X dan Y, kita perlu meng-clamping keduanya, jadi ketika update posisi kita harus punya pencegah supaya angkanya untuk diatas 0 dan dibawah batas dari ukuran window.
Kira-kira beginilah fungsinya:
function clamp(number, min,max)
-- untuk ngecek kalo angkanya kebalik
if min >= max then
local oldmax = max
max = min
min = oldmax
end
-- kalo angka sudah max, balikin nilai max aja
if number >= max then
return max
end
-- keak yang max, untuk nilai minimum
if number <= min then
return min
end
return number
end
Lalu kita ubah kode di bagian laifsaikel love.update:
function love.update(dt)
local window_x_limit = 800
local window_y_limit = 600
if love.keyboard.isDown("left") then
nyo.pos_x = clamp(nyo.pos_x - nyo.speed, 0, window_x_limit)
elseif love.keyboard.isDown("right") then
nyo.pos_x = clamp(nyo.pos_x + nyo.speed, 0, window_x_limit)
elseif love.keyboard.isDown("up") then
nyo.pos_y = clamp(nyo.pos_y - nyo.speed, 0, window_y_limit)
elseif love.keyboard.isDown("down") then
nyo.pos_y = clamp(nyo.pos_y + nyo.speed, 0, window_y_limit)
end
end
Penjelasan:
- variabel
window_x_limit
, ini placeholder untuk lebar window, begitu juga yangwindow_y_limit
untuk tinggi window. - Lalu kita terapkan fungsi clamp ke hasil hitungan posisi Nyo, contohnya kaya gini
clamp(nyo.pos_x - nyo.speed, 0, window_x_limit)
:- Argument param
number
-nya (nyo.pos_x - nyo.speed
) hitungan nilai posisi yang di-clamping. - Argumen param
min
(0) untuk batas nilai bawah danmax
(window_x_limit
) untuk batasan nilai atas yang boleh aja.
- Argument param
Posisi X dan Y sudah berhenti tapi masih ga muncul ?
Ini terjadi karena kita mengabaikan ukuran ruang dari gambar karakter. Gambar nyo-nyo punya resolusi 48 x 48, kok tau? lah kan saya yang gambar. Jadi ini menangani ini kita harus menyesuaikan batas window dengan ukuran ruang gambar.
Kasus ini dikarenakan, titik perhitungan posisi gambar (nyo.image
) dimulai dari sudut kiri atas maka untuk menampilkan gambar kita perlu mengompensasi batas window dengan luas gambar dari tiap-tiap sumbu saat clamping.
Ingat untuk kompensasi batas window ini hanya untuk gerakan yang menjauhi titik 0 yakni gerakan kekanan dan kebawah.
-- sesuaikan dengan kode yang ada di fungsi love.update()
elseif love.keyboard.isDown("right") then
nyo.pos_x = clamp(nyo.pos_x + nyo.speed, 0, window_x_limit - nyo.image:getWidth())
elseif love.keyboard.isDown("down") then
nyo.pos_y = clamp(nyo.pos_y + nyo.speed, 0, window_y_limit - nyo.image:getHeight())
end
Penjelasan:
- Perubahan kode disini mengurangi batas window dengan ukuran luas dan tinggi gambar Nyo. Batas window sumbu X dikurangi dengan luas gambar dan batas window sumbu y dikurang dengan tinggi gambar.
- fungsi
nyo.image:getHeight()
untuk mengambil ukuran tinggi dari gambar Nyo dan fungsinyo.image:getWidth()
untuk luas.
Hasilnya seperti ini:
Seperti yang terlihat pada debugger minimalis kita, ia berhenti pada posisi (752,552) yang bila ditambah (48,48) akan menjadi (800,600) yakni ukuran window.
Angka diluar formula kita
Karakter kita boleh bergerak, namun pergerakan kita berdasarkan perhitungan matematis saja dan mengabaikan faktor FPS. Apa masalahnya jika kita mengabaikan FPS ? Perhitungan kita akan berantakan ketika FPS terganggu katakan lah FPS berubah menjadi 0, angka ini diluar kendali kita langsung sebab dihasilkan oleh kinerja mesin. Kecepatan pergerakan 10 piksel kita dihitung dalam setiap eksekusi frame alias 10px per frame bukan 10px per detik.
Delta time datang menjadi solusi dari problem ini, delta time adalah selisih waktu render window terakhir dengan window sekarang. Gunanya untuk menyesuaikan perhitungan yang tertinggal bila terjadi fluktuasi FPS yang tak terduga. Ini ketika ngelag beberapa game akan mengkompensasi keterlambatan dengan mempercepat gerakan.
Mari kita terapkan perhitungan delta time, karena angka yang membuat karakter kita bergerak ada nyo.speed
maka nilai ini perlu disesuaikan dengan delta time, caranya? dengan diceburkan ke kali, dikalikan.
function love.update(dt)
local window_x_limit = 800
local window_y_limit = 600
local accel = math.abs(nyo.speed * dt)
if love.keyboard.isDown("left") then
nyo.pos_x = clamp(nyo.pos_x - accel, 0, window_x_limit)
elseif love.keyboard.isDown("right") then
nyo.pos_x = clamp(nyo.pos_x + accel, 0, window_x_limit - nyo.image:getWidth())
elseif love.keyboard.isDown("up") then
nyo.pos_y = clamp(nyo.pos_y - accel, 0, window_y_limit)
elseif love.keyboard.isDown("down") then
nyo.pos_y = clamp(nyo.pos_y + accel, 0, window_y_limit - nyo.image:getHeight())
end
end
Penjelasan:
- Perhitungan untuk kecepatan nyo yang disesuaikan dengan delta time (
dt
) akan dihitung diawal dan disimpan dalam variableaccel
(Akselerasi). - Akselerasi berbeda dengan kecepatan, kecepatan itu perpindahan objek dalam satu waktu sedangkan akselerasi perubahan kecepatan dalam satu waktu, dalam kasus ini perubahan kecepatan dipengaruhi oleh jeda antara render frame alias delta time.
Kenapa tadinya Nyo cepat, setelah disesuaikan malah melambat ? karena pengerakan berubah menjadi piksel per detik, supaya lebih cepat coba naikan kecepatan (nyo.speed
) sekitar 200 sampai 400 dan rasakan bedanya.
Penutup
Achievement Unlocked : Gambar bergerak
Ini bisa dibilang cornerstone untuk mekanik game semacam top-down, platformer dan semacamnya yang perlu interaksi kontinu.
Next up, bila sempat ingin melanjutkan malah tumbukan atar objek alias Nyo-nyo bakal ada temen, musuh alias interaksi eksternal dengan objek lain alias NPC (non-playable character).
Top comments (0)