Seringkali saya ingin menggunakan nilai kecepatan seperti 2,5 untuk memindahkan karakter saya dalam game berbasis pixel. Deteksi tabrakan umumnya akan lebih sulit jika saya melakukannya. Jadi saya akhirnya melakukan sesuatu seperti ini:
moveX(2);
if (ticks % 2 == 0) { // or if (moveTime % 2 == 0)
moveX(1);
}
Saya merasa ngeri di dalam setiap kali saya harus menulis itu, apakah ada cara yang lebih bersih untuk memindahkan karakter dengan nilai kecepatan non-integer atau akankah saya tetap terjebak melakukan ini selamanya?
Jawaban:
Bresenham
Di masa lalu, ketika orang masih menulis rutin video dasar mereka sendiri untuk menggambar garis dan lingkaran, itu tidak pernah terdengar menggunakan algoritma garis Bresenham untuk itu.
Bresenham memecahkan masalah ini: Anda ingin menggambar garis pada layar yang menggerakkan
dx
piksel dalam arah horizontal sementara pada saat yang sama menjangkaudy
piksel dalam arah vertikal. Ada karakter "ringan" yang melekat pada garis; bahkan jika Anda memiliki piksel bilangan bulat, Anda berakhir dengan kecenderungan rasional.Algoritme harus cepat, yang artinya dapat menggunakan integer aritmatika saja; dan itu juga hilang tanpa penggandaan atau pembagian, hanya penambahan dan pengurangan.
Anda dapat menyesuaikan itu untuk kasus Anda:
"x / y" di sini bukan lokasi di layar, tetapi nilai salah satu dimensi Anda dalam waktu. Jelas, jika sprite Anda berjalan dengan arah yang sewenang-wenang melintasi layar, Anda akan memiliki beberapa Bresenhams yang berjalan secara terpisah, 2 untuk 2D, 3 untuk 3D.
Contoh
Katakanlah Anda ingin memindahkan karakter Anda dalam gerakan sederhana dari 0 hingga 25 di sepanjang salah satu sumbu Anda. Saat bergerak dengan kecepatan 2.5, ia akan muncul di frame 10.
Ini sama dengan "menggambar garis" dari (0,0) hingga (10,25). Ambil algoritme garis Bresenham dan biarkan berjalan. Jika Anda melakukannya dengan benar (dan ketika Anda mempelajarinya, itu akan dengan cepat menjadi jelas bagaimana Anda melakukannya dengan benar), maka itu akan menghasilkan 11 "poin" untuk Anda (0,0), (1,2), (2, 5), (3,7), (4,10) ... (10,25).
Petunjuk adaptasi
Jika Anda google algoritma itu dan menemukan beberapa kode (Wikipedia memiliki perjanjian yang cukup besar di dalamnya), ada beberapa hal yang perlu Anda perhatikan:
dx
dandy
. Anda tertarik pada satu kasus khusus (yaitu, Anda tidak akan pernah memilikinyadx=0
).dx
dandy
positif, negatif, dan juga apakahabs(dx)>abs(dy)
atau tidak. Anda tentu juga memilih apa yang Anda butuhkan di sini. Anda harus memastikan secara khusus bahwa arah yang ditingkatkan oleh1
setiap tick selalu merupakan arah "jam" Anda.Jika Anda menerapkan penyederhanaan ini, hasilnya akan sangat sederhana, dan singkirkan semua realita.
sumber
Ada cara hebat untuk melakukan apa yang Anda inginkan.
Selain
float
kecepatan, Anda harus memilikifloat
variabel kedua yang akan berisi dan mengakumulasikan perbedaan antara kecepatan nyata dan kecepatan bulat . Perbedaan ini kemudian dikombinasikan dengan kecepatan itu sendiri.Keluaran:
sumber
Gunakan nilai mengambang untuk gerakan dan nilai integer untuk tabrakan dan rendering.
Ini sebuah contoh:
Ketika Anda bergerak, Anda menggunakan
move()
yang mengakumulasi posisi fraksional. Tetapi tabrakan dan rendering dapat menangani posisi integral dengan menggunakangetPosition()
fungsi tersebut.sumber