evilfactorylabs

Cover image for Gambar Bergerak dengan Kibot di Love2D
Mabinogion
Mabinogion

Posted on • Updated on

Gambar Bergerak dengan Kibot di Love2D

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Penjelasan:

  • nyo = {} adalah data berbentuk table, map atau pasangan key-value, mirip JSON la.
  • nyo.image = love....("nyo-nyo.png"), kita membuat key bernama image dengan data love.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 objek nyo 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
Enter fullscreen mode Exit fullscreen mode

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 tapi resource hungry karena perform lebih sering.
  • Alasan kenapa pakai love.update ketimbang love.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
Enter fullscreen mode Exit fullscreen mode

Hasilnya kayak gini:

gambar nyo-nyo dengan tampilan posisi x dan y secara tekstual

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Penjelasan:

  • variabel window_x_limit, ini placeholder untuk lebar window, begitu juga yang window_y_limit untuk tinggi window.
  • Lalu kita terapkan fungsi clamp ke hasil hitungan posisi Nyo, contohnya kaya giniclamp(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 dan max (window_x_limit) untuk batasan nilai atas yang boleh aja.

Posisi X dan Y sudah berhenti tapi masih ga muncul ?

sudah mentok sumbu x tapi karakter malah hilang dan nilai x tidak berubah

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

Enter fullscreen mode Exit fullscreen mode

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 fungsi nyo.image:getWidth() untuk luas.

Hasilnya seperti ini:

posisi nyo dipojok kanan bawah nunjukan batas clamping window telah disesuaikan oleh ukuran gambar nyo

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
Enter fullscreen mode Exit fullscreen mode

Penjelasan:

  • Perhitungan untuk kecepatan nyo yang disesuaikan dengan delta time (dt) akan dihitung diawal dan disimpan dalam variable accel (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).

referensi lanjutan

Top comments (0)