Saat ini saya mulai belajar OpenGL di sekolah, dan saya mulai membuat permainan sederhana beberapa hari yang lalu (sendirian, bukan untuk sekolah). Saya menggunakan freeglut, dan saya sedang membuatnya dalam C, jadi untuk loop game saya, saya benar-benar baru saja menggunakan fungsi yang saya buat glutIdleFunc
untuk memperbarui semua gambar dan fisika dalam satu pass. Ini bagus untuk animasi sederhana yang saya tidak terlalu peduli tentang frame rate, tetapi karena permainan ini sebagian besar berbasis fisika, saya benar-benar ingin (perlu) mengikat seberapa cepat pembaruannya.
Jadi upaya pertama saya adalah memiliki fungsi yang saya lewati glutIdleFunc
( myIdle()
) untuk melacak berapa banyak waktu yang telah berlalu sejak panggilan sebelumnya, dan memperbarui fisika (dan saat ini grafik) setiap milidetik. Saya biasa timeGetTime()
melakukan ini (dengan menggunakan <windows.h>
). Dan ini membuat saya berpikir, apakah menggunakan fungsi idle benar-benar cara yang baik untuk melakukan loop game?
Pertanyaan saya adalah, apa cara yang lebih baik untuk mengimplementasikan loop game di OpenGL? Haruskah saya menghindari menggunakan fungsi idle?
Jawaban:
Jawaban sederhananya adalah tidak, Anda tidak ingin menggunakan panggilan balik glutIdleFunc dalam gim yang memiliki semacam simulasi. Alasan untuk ini adalah bahwa fungsi ini menceraikan animasi dan menggambar kode dari penanganan acara jendela tetapi tidak asinkron. Dengan kata lain, menerima dan menyerahkan acara jendela warung menggambar kode (atau apa pun yang Anda masukkan dalam panggilan balik ini), ini sangat baik untuk aplikasi interaktif (berinteraksi, kemudian merespons), tetapi tidak untuk permainan di mana keadaan fisika atau permainan harus maju independen dari interaksi atau render waktu.
Anda ingin sepenuhnya memisahkan penanganan input, status gim, dan menggambar kode. Ada solusi mudah dan bersih untuk ini yang tidak melibatkan perpustakaan grafis secara langsung (yaitu portabel dan mudah divisualisasikan); Anda ingin seluruh loop permainan menghasilkan waktu dan membuat simulasi menghabiskan waktu yang dihasilkan (dalam potongan). Namun kuncinya adalah untuk mengintegrasikan jumlah waktu simulasi Anda dikonsumsi ke animasi Anda.
Penjelasan dan tutorial terbaik yang saya temukan tentang ini adalah Fix Your Timestep milik Glenn Fiedler
Tutorial ini memiliki perawatan lengkap, namun jika Anda tidak memiliki simulasi fisika yang sebenarnya , Anda dapat melewatkan integrasi sebenarnya tetapi loop dasar masih bermuara pada (dalam kode-pseudo-verbose):
Dengan melakukannya dengan cara ini, warung dalam kode render, penanganan input, atau sistem operasi Anda tidak menyebabkan status permainan Anda tertinggal. Metode ini juga portabel dan perpustakaan grafis independen.
GLUT adalah pustaka yang bagus namun sangat dikendalikan oleh peristiwa. Anda mendaftarkan panggilan balik dan mematikan loop utama. Anda selalu menyerahkan kontrol loop utama Anda menggunakan GLUT. Ada hack untuk mengatasinya , Anda juga dapat memalsukan loop eksternal menggunakan timer dan semacamnya, tetapi perpustakaan lain mungkin merupakan cara yang lebih baik (lebih mudah). Ada banyak alternatif, berikut adalah beberapa (yang dengan dokumentasi bagus dan tutorial cepat):
sumber
Saya pikir
glutIdleFunc
baik-baik saja; itu pada dasarnya apa yang akhirnya Anda lakukan dengan tangan, jika Anda tidak menggunakannya. Tidak peduli apa yang akan Anda miliki dengan loop ketat yang tidak disebut dalam pola tetap, dan Anda harus membuat pilihan apakah Anda ingin mengubahnya menjadi loop waktu tetap atau menjadikannya loop variabel waktu dan membuat yakin semua akun matematika Anda untuk waktu interpolasi. Atau bahkan campuran dari ini, entah bagaimana.Anda tentu dapat memiliki
myIdle
fungsi yang Anda masukiglutIdleFunc
, dan di dalamnya, mengukur waktu yang telah berlalu, membaginya dengan stempel waktu Anda yang tetap, dan memanggil fungsi lain yang berkali-kali.Inilah yang tidak boleh dilakukan:
fixedTimestep tidak akan dipanggil setiap 10 milidetik. Bahkan itu akan berjalan lebih lambat daripada waktu nyata, dan Anda mungkin berakhir dengan angka-angka palsu untuk mengkompensasi ketika benar-benar akar masalahnya terletak pada hilangnya sisanya ketika Anda membagi
timeDifference
dengan 10.Sebagai gantinya, lakukan sesuatu seperti ini:
Sekarang struktur loop ini memastikan bahwa Anda
fixedTimestep
fungsi akan dipanggil sekali per 10 milidetik, tanpa kehilangan milidetik sebagai sisa atau semacamnya.Karena sifat multitasking sistem operasi, Anda tidak dapat mengandalkan fungsi yang dipanggil tepat setiap 10 milidetik; tetapi loop di atas akan terjadi cukup cepat sehingga diharapkan akan cukup dekat, dan Anda dapat mengasumsikan bahwa setiap panggilan
fixedTimestep
akan meningkatkan simulasi Anda senilai 10 milidetik.Baca juga jawaban ini dan terutama tautan yang disediakan dalam jawaban.
sumber