Ada puluhan artikel, buku, dan diskusi di luar sana di loop game. Namun, saya cukup sering menemukan sesuatu seperti ini:
while(running)
{
processInput();
while(isTimeForUpdate)
{
update();
}
render();
}
Apa yang pada dasarnya mengganggu saya tentang pendekatan ini adalah rendering "update-independent", mis. Membuat sebuah bingkai ketika tidak ada perubahan sama sekali. Jadi pertanyaan saya adalah mengapa pendekatan ini sering diajarkan?
while (isTimeForUpdate)
, bukanif (isTimeForUpdate)
. Tujuan utamanya bukan padarender()
saat belum adaupdate()
, tetapi untukupdate()
berulang kali di antararender()
s. Apapun, kedua situasi memiliki kegunaan yang valid. Yang pertama akan valid jika negara dapat mengubah di luarupdate
fungsi Anda , misalnya, mengubah apa yang diberikan berdasarkan keadaan implisit seperti waktu saat ini. Yang terakhir ini valid karena memberi mesin fisika Anda kemungkinan untuk melakukan banyak pembaruan kecil dan akurat, yang misalnya mengurangi kemungkinan 'melengkung' melalui rintangan.Jawaban:
Ada sejarah panjang tentang bagaimana kami sampai di kebaktian bersama ini, dengan banyak tantangan yang menarik di sepanjang jalan, jadi saya akan mencoba memotivasinya secara bertahap:
1. Masalah: Perangkat berjalan dengan kecepatan berbeda
Pernah mencoba memainkan game DOS lama di PC modern, dan ini berjalan sangat cepat - hanya blur?
Banyak game lama memiliki loop pembaruan yang sangat naif - mereka mengumpulkan input, memperbarui status game, dan merender secepat yang dimungkinkan oleh hardware, tanpa memperhitungkan berapa lama waktu yang telah berlalu. Yang berarti begitu perangkat keras berubah, gameplay berubah.
Kami umumnya ingin para pemain kami memiliki pengalaman dan rasa permainan yang konsisten pada berbagai perangkat, (selama mereka memenuhi beberapa spesifikasi minimum) apakah mereka menggunakan ponsel tahun lalu atau model terbaru, desktop gaming top-end atau laptop tingkat menengah.
Khususnya, untuk permainan yang kompetitif (baik multipemain atau melalui papan peringkat) kami tidak ingin pemain yang berjalan di perangkat tertentu memiliki keunggulan dibandingkan yang lain karena mereka dapat berlari lebih cepat atau memiliki lebih banyak waktu untuk bereaksi.
Solusi jitu di sini adalah untuk mengunci tingkat di mana kami melakukan pembaruan keadaan gameplay. Dengan begitu kami bisa menjamin hasilnya akan selalu sama.
2. Jadi, mengapa tidak hanya mengunci framerate (mis. Menggunakan VSync) dan masih menjalankan pembaruan status gameplay & rendering di lockstep?
Ini bisa berhasil, tetapi tidak selalu cocok untuk audiens. Ada waktu yang lama ketika berlari dengan kecepatan 30 fps dianggap sebagai standar emas untuk gim. Sekarang, pemain secara rutin mengharapkan 60 fps sebagai bilah minimum, terutama di game aksi multipemain, dan beberapa judul yang lebih tua sekarang terlihat sangat berombak karena harapan kami telah berubah. Ada juga grup vokal pemain PC yang secara khusus menolak kunci framerate. Mereka membayar banyak untuk perangkat keras mereka yang berdarah, dan ingin dapat menggunakan otot komputasi itu untuk menghasilkan rendering, kesetiaan tertinggi, yang mampu dilakukannya.
Khususnya di VR, framerate adalah raja, dan standarnya terus merayap. Di awal kebangkitan VR baru-baru ini, game sering berlari sekitar 60 fps. Sekarang 90 lebih standar, dan harware seperti PSVR mulai mendukung 120. Ini mungkin terus meningkat. Jadi, jika sebuah game VR membatasi framerate-nya dengan apa yang bisa dilakukan & diterima hari ini, itu mungkin tertinggal karena hardware dan ekspektasi berkembang lebih jauh.
(Sebagai aturan, berhati-hatilah ketika diberi tahu "pemain tidak dapat melihat apa pun lebih cepat dari XXX" karena biasanya didasarkan pada jenis "persepsi" tertentu, seperti mengenali bingkai secara berurutan. Persepsi tentang kontinuitas gerak umumnya jauh lebih banyak. sensitif.)
Masalah terakhir di sini adalah bahwa permainan menggunakan framerate yang dikunci juga perlu konservatif - jika Anda pernah menemukan momen dalam permainan di mana Anda memperbarui & menampilkan jumlah objek yang luar biasa tinggi, Anda tidak ingin ketinggalan bingkai Anda tenggat waktu dan menyebabkan gagap atau halangan yang nyata. Jadi Anda perlu mengatur anggaran konten Anda cukup rendah untuk meninggalkan ruang kepala, atau berinvestasi dalam fitur penyesuaian kualitas dinamis yang lebih rumit untuk menghindari mengelompokkan seluruh pengalaman bermain dengan kinerja terburuk pada perangkat keras min-spec.
Ini bisa sangat bermasalah jika masalah kinerja muncul terlambat dalam pengembangan, ketika semua sistem Anda yang ada dibangun & disetel dengan asumsi framerate rendering berbaris yang sekarang Anda tidak selalu dapat menekan. Pembaruan decoupling & rendering rate memberi lebih banyak fleksibilitas untuk berurusan dengan variabilitas kinerja.
3. Tidak memperbarui pada catatan waktu yang tetap memiliki masalah yang sama seperti (2)?
Saya pikir ini adalah inti dari pertanyaan asli: jika kita memisahkan pembaruan kita dan kadang-kadang membuat dua frame tanpa pembaruan status permainan di antara keduanya, maka bukankah itu sama dengan rendering langkah-langkah di framerate yang lebih rendah, karena tidak ada perubahan yang terlihat pada layar?
Sebenarnya ada beberapa cara permainan menggunakan decoupling pembaruan ini untuk efek yang baik:
a) Tingkat pembaruan bisa lebih cepat daripada framerate yang diberikan
Sebagai catatan tyjkenn dalam jawaban lain, fisika khususnya sering kali melangkah pada frekuensi yang lebih tinggi daripada rendering, yang membantu meminimalkan kesalahan integrasi dan memberikan tabrakan yang lebih akurat. Jadi, daripada memiliki 0 atau 1 pembaruan antara frame yang diberikan Anda mungkin memiliki 5 atau 10 atau 50.
Sekarang rendering pemain pada 120 fps bisa mendapatkan 2 pembaruan per frame, sedangkan pemain pada rendering hardware spec yang lebih rendah pada 30 fps mendapat 8 pembaruan per frame, dan kedua game mereka berjalan pada kecepatan gameplay-ticks-per-realtime-second yang sama. Perangkat keras yang lebih baik membuatnya terlihat lebih halus, tetapi tidak secara radikal mengubah cara kerja gameplay.
Ada risiko di sini bahwa, jika laju pembaruan tidak cocok dengan framerate, Anda bisa mendapatkan "frekuensi ketukan" di antara keduanya . Misalnya. kebanyakan frame kita punya cukup waktu untuk 4 pembaruan keadaan permainan dan sedikit sisa, maka setiap kali kita cukup menyimpan hingga 5 pembaruan dalam satu frame, membuat sedikit lompatan atau gagap dalam gerakan. Ini dapat diatasi dengan ...
b) Menginterpolasi (atau mengekstrapolasi) status game di antara pembaruan
Di sini kita akan sering membiarkan status permainan menjalani satu stempel waktu tetap di masa mendatang, dan menyimpan informasi yang cukup dari 2 status terbaru yang dapat kita berikan titik arbitrer di antara mereka. Kemudian ketika kami siap untuk menampilkan bingkai baru di layar, kami berbaur dengan momen yang tepat hanya untuk tujuan tampilan (mis. Kami tidak mengubah keadaan gameplay yang mendasarinya di sini)
Ketika dilakukan dengan benar ini membuat gerakan terasa mentega halus, dan bahkan membantu untuk menutupi beberapa fluktuasi framerate, selama kita tidak jatuh terlalu rendah.
c) Menambahkan kehalusan pada perubahan non-gameplay-state
Bahkan tanpa interpolasi keadaan gameplay, kita masih bisa mendapatkan beberapa kemenangan mulus.
Perubahan visual murni seperti animasi karakter, sistem partikel atau VFX, dan elemen antarmuka pengguna seperti HUD, sering diperbarui secara terpisah dari catatan waktu tetap keadaan gameplay. Ini berarti jika kita mencentang status gameplay beberapa kali per frame, kami tidak membayar biaya dengan setiap centang - hanya pada render pass terakhir. Sebagai gantinya, kami menskalakan kecepatan pemutaran efek ini agar sesuai dengan panjang frame, sehingga mereka bermain semulus rendering framerate memungkinkan, tanpa memengaruhi kecepatan atau keadilan game seperti yang dibahas dalam (1).
Pergerakan kamera juga bisa melakukan ini - terutama di VR, kadang-kadang kami akan menunjukkan frame yang sama lebih dari satu kali, tetapi memproyeksikan ulang untuk memperhitungkan pergerakan kepala pemain di antaranya , sehingga kami dapat meningkatkan latensi dan kenyamanan yang dirasakan, bahkan jika kami bisa asli membuat semuanya secepat itu. Beberapa sistem streaming game (di mana game berjalan di server dan pemain hanya menjalankan thin client) menggunakan versi ini juga.
4. Mengapa tidak menggunakan gaya (c) itu untuk semuanya? Jika itu berfungsi untuk animasi dan UI, tidak bisakah kita cukup skala pembaruan keadaan gameplay kami agar sesuai dengan framerate saat ini?
Ya * ini mungkin, tapi tidak itu tidak sederhana.
Jawaban ini sudah agak lama jadi saya tidak akan membahas semua detail yang berdarah, hanya ringkasan singkat:
Mengalikan dengan
deltaTime
karya untuk menyesuaikan dengan pembaruan panjang variabel untuk perubahan linier (mis. Gerakan dengan kecepatan konstan, hitungan mundur pengatur waktu, atau berkembang di sepanjang garis waktu animasi)Sayangnya, banyak aspek permainan yang tidak linier . Bahkan sesuatu yang sesederhana gravitasi menuntut teknik integrasi yang lebih canggih atau resolusi yang lebih tinggi untuk menghindari hasil yang berbeda di bawah framerate yang berbeda-beda. Input dan kontrol pemain itu sendiri merupakan sumber besar non-linearitas.
Secara khusus, hasil deteksi dan resolusi tabrakan diskrit tergantung pada tingkat pembaruan, yang mengarah ke kesalahan tunneling dan jittering jika frame terlalu lama. Jadi framerate variabel memaksa kita untuk menggunakan metode pendeteksian tabrakan berkelanjutan yang lebih kompleks / mahal pada lebih banyak konten kita, atau mentolerir variabilitas dalam fisika kita. Bahkan deteksi tabrakan terus menerus menghadapi tantangan ketika benda bergerak dalam busur, membutuhkan waktu yang lebih singkat ...
Jadi, dalam kasus umum untuk permainan kompleksitas sedang, mempertahankan perilaku konsisten & keadilan sepenuhnya melalui
deltaTime
penskalaan adalah di antara yang sangat sulit & pemeliharaan yang intensif hingga tidak mungkin.Menstandarkan tingkat pembaruan memungkinkan kami menjamin perilaku yang lebih konsisten di berbagai kondisi , seringkali dengan kode yang lebih sederhana.
Menjaga agar laju pembaruan dipisahkan dari rendering memberi kami fleksibilitas untuk mengontrol kelancaran dan kinerja pengalaman tanpa mengubah logika gameplay .
Bahkan saat itu kita tidak pernah mendapatkan kemerdekaan framerate yang benar-benar "sempurna" tetapi seperti banyak pendekatan dalam game itu memberi kita metode yang terkendali untuk memanggil "cukup baik" untuk kebutuhan game tertentu. Itu sebabnya itu umumnya diajarkan sebagai titik awal yang bermanfaat.
sumber
read-update-render
, latensi kasus terburuk kami adalah 17 ms (mengabaikan grafik pipa dan menampilkan latensi untuk saat ini). Dengan(read-update)x(n>1)-render
loop terpisah pada framerate yang sama, latensi kasus terburuk kami hanya bisa sama atau lebih baik karena kami memeriksa & bertindak atas input sesering atau lebih. :)Jawaban lainnya bagus dan bicarakan mengapa loop game ada dan harus terpisah dari loop render. Namun, seperti untuk contoh spesifik "Mengapa merender bingkai ketika belum ada perubahan?" Ini benar-benar hanya berkaitan dengan perangkat keras dan kompleksitas.
Kartu video adalah mesin negara dan mereka sangat baik dalam melakukan hal yang sama berulang kali. Jika Anda hanya membuat hal-hal yang berubah, itu sebenarnya lebih mahal, bukan lebih sedikit. Dalam sebagian besar skenario, tidak ada banyak hal yang statis, jika Anda bergerak sedikit ke kiri dalam permainan FPS, Anda telah mengubah data piksel 98% barang di layar, Anda mungkin juga membuat seluruh frame.
Tetapi terutama, kompleksitas. Melacak segala sesuatu yang berubah saat melakukan pembaruan jauh lebih mahal karena Anda harus mengerjakan ulang semuanya atau melacak hasil lama dari beberapa algoritma, membandingkannya dengan hasil baru dan hanya membuat piksel itu jika perubahannya berbeda. Tergantung sistemnya.
Desain perangkat keras dll. Sebagian besar dioptimalkan untuk konvensi saat ini, dan mesin negara telah menjadi model yang baik untuk memulai.
sumber
Rendering biasanya merupakan proses paling lambat dalam loop game. Manusia tidak mudah melihat perbedaan dalam frame rate lebih cepat dari 60, sehingga sering kali kurang penting untuk membuang waktu rendering lebih cepat dari itu. Namun, ada proses lain yang akan mendapat manfaat lebih dari tingkat yang lebih cepat. Fisika adalah satu. Perubahan yang terlalu besar dalam satu loop dapat menyebabkan objek mengalami glitch tepat melewati dinding. Mungkin ada cara untuk mengatasi kesalahan tabrakan sederhana pada kenaikan yang lebih besar, tetapi untuk banyak interaksi fisika yang kompleks, Anda tidak akan mendapatkan akurasi yang sama. Jika loop fisika dijalankan lebih sering, ada kemungkinan glitches lebih kecil, karena objek dapat dipindahkan secara bertahap lebih kecil tanpa di-render setiap saat. Lebih banyak sumber daya menuju mesin fisika yang sensitif dan lebih sedikit yang terbuang untuk menggambar lebih banyak frame yang tidak dapat dilihat pengguna.
Ini sangat penting dalam game yang lebih intensif grafis. Jika ada satu render untuk setiap loop game, dan seorang pemain tidak memiliki mesin yang paling kuat, mungkin ada poin dalam game di mana fps turun menjadi 30 atau 40. Meskipun ini masih merupakan frame rate yang tidak sepenuhnya mengerikan, permainan akan mulai menjadi agak lambat jika kami mencoba menjaga setiap perubahan fisika cukup kecil untuk menghindari kesalahan. Pemain akan kesal karena karakternya berjalan hanya setengah dari kecepatan normal. Namun, jika kecepatan rendering tidak tergantung dari sisa loop, pemain akan dapat tetap pada kecepatan berjalan tetap meskipun penurunan frame rate.
sumber
Sebuah konstruksi seperti yang ada di pertanyaan Anda dapat masuk akal jika subsistem rendering memiliki gagasan "waktu yang berlalu sejak render terakhir" .
Pertimbangkan, misalnya, sebuah pendekatan di mana posisi suatu objek di dunia game diwakili melalui
(x,y,z)
koordinat tetap dengan pendekatan yang juga menyimpan vektor gerakan saat ini(dx,dy,dz)
. Sekarang, Anda bisa menulis lingkaran permainan Anda sehingga perubahan posisi harus terjadi dalamupdate
metode, tetapi Anda juga bisa mendesainnya sehingga perubahan gerakan harus terjadi selamaupdate
. Dengan pendekatan yang terakhir, meskipun kondisi permainan Anda sebenarnya tidak akan berubah sampai yang berikutnyaupdate
,render
-fungsi yang disebut pada frekuensi yang lebih tinggi sudah bisa menarik objek pada posisi yang sedikit diperbarui. Walaupun ini secara teknis mengarah pada perbedaan antara apa yang Anda lihat dan apa yang diwakili secara internal, perbedaannya cukup kecil sehingga tidak masalah untuk sebagian besar aspek praktis, namun memungkinkan animasi terlihat jauh lebih halus.Memprediksi "masa depan" dari kondisi gim Anda (meskipun ada risiko salah) dapat menjadi ide bagus ketika Anda mengambil contoh latensi input jaringan ke dalam akun.
sumber
Selain jawaban lain ...
Memeriksa perubahan keadaan membutuhkan pemrosesan yang signifikan. Jika diperlukan waktu pemrosesan yang serupa (atau lebih!) Untuk memeriksa perubahan, dibandingkan dengan benar-benar melakukan pemrosesan, Anda benar-benar belum membuat situasi lebih baik. Dalam hal rendering gambar, seperti yang dikatakan @Waddles, kartu video benar - benar bagus dalam melakukan hal bodoh yang sama berulang-ulang, dan itu lebih mahal untuk memeriksa setiap potongan data untuk perubahan daripada hanya dengan mentransfernya ke seberang ke kartu video untuk diproses. Juga jika rendering adalah gameplay maka itu benar-benar tidak mungkin untuk layar tidak berubah dalam centang terakhir.
Anda juga mengasumsikan bahwa rendering membutuhkan waktu prosesor yang signifikan. Ini sangat tergantung pada prosesor dan kartu grafis Anda. Selama bertahun-tahun sekarang, fokusnya adalah pada pembongkaran pekerjaan rendering yang semakin canggih ke kartu grafis dan mengurangi input rendering yang dibutuhkan dari prosesor. Idealnya
render()
panggilan prosesor hanya perlu mengatur transfer DMA dan hanya itu. Mendapatkan data ke kartu grafis kemudian didelegasikan ke pengontrol memori, dan menghasilkan gambar didelegasikan ke kartu grafis. Mereka dapat melakukan itu di waktu mereka sendiri, sementara prosesor secara paralelmenjalankan dengan fisika, mesin gameplay dan semua hal lain yang prosesor lebih baik. Kenyataannya jauh lebih rumit dari itu, tetapi kemampuan untuk membongkar pekerjaan ke bagian lain dari sistem juga merupakan faktor yang signifikan.sumber