Haruskah loop game didasarkan pada langkah waktu tetap atau variabel? Apakah seseorang selalu lebih unggul, atau apakah pilihan yang tepat bervariasi berdasarkan permainan?
Langkah waktu variabel
Pembaruan fisika diteruskan argumen "waktu berlalu sejak pembaruan terakhir" dan karenanya bergantung pada framerate. Ini mungkin berarti melakukan perhitungan sebagai position += distancePerSecond * timeElapsed
.
Kelebihan : halus, lebih mudah
dikodekan Kontra : non-deterministik, tidak dapat diprediksi pada langkah yang sangat kecil atau besar
contoh deWiTTERS :
while( game_is_running ) {
prev_frame_tick = curr_frame_tick;
curr_frame_tick = GetTickCount();
update( curr_frame_tick - prev_frame_tick );
render();
}
Memperbaiki langkah waktu
Pembaruan bahkan mungkin tidak menerima "waktu yang berlalu", karena mereka menganggap setiap pembaruan adalah untuk periode waktu yang tetap. Perhitungan dapat dilakukan sebagai position += distancePerUpdate
. Contohnya termasuk interpolasi selama render.
Kelebihan : dapat diprediksi, deterministik (lebih mudah untuk sinkronisasi jaringan?), Kode perhitungan yang lebih jelas
Kontra : tidak disinkronkan untuk memantau v-sinkronisasi (menyebabkan grafik gelisah kecuali jika Anda melakukan interpolasi), frame rate maks terbatas (kecuali jika Anda interpolasi), sulit untuk bekerja dalam kerangka kerja yang anggap langkah waktu variabel (seperti Pyglet atau Flixel )
contoh deWiTTERS :
while( game_is_running ) {
while( GetTickCount() > next_game_tick ) {
update();
next_game_tick += SKIP_TICKS;
}
interpolation = float( GetTickCount() + SKIP_TICKS - next_game_tick )
/ float( SKIP_TICKS );
render( interpolation );
}
Beberapa sumber daya
- Gaffer di permainan: Perbaiki cap waktu Anda!
- artikel loop game deWitter
- FPS Quake 3 memengaruhi fisika lompat — mungkin alasan mengapa Doom 3 dikunci hingga 60fps?
- Flixel membutuhkan tanda waktu variabel (saya pikir ini ditentukan oleh Flash) sedangkan Flashpunk memungkinkan kedua jenis.
- Manual Box2D § Mensimulasikan Dunia Box2D menyarankan untuk menggunakan langkah waktu yang konstan.
sumber
Jawaban:
Ada dua masalah yang terkait dengan pertanyaan itu.
Dalam Glen fielder's Perbaiki langkah waktu Anda katanya untuk "Bebaskan Fisika". Itu berarti tingkat pembaruan fisika Anda tidak harus dikaitkan dengan frame rate Anda.
Dalam rekomendasi Erin Catto untuk Box2D ia juga mengadvokasi ini.
Haruskah tingkat langkah Fisika dikaitkan dengan frame rate Anda? Tidak.
Pikiran Erin tentang langkah tetap vs variabel melangkah:
Pikiran Glen tentang melangkah tetap vs variabel:
Haruskah fisika diinjak dengan delta konstan? Iya.
Cara untuk melangkah fisika dengan delta konstan dan tidak mengikat laju pembaruan fisika Anda ke frame rate masih menggunakan akumulator waktu. Dalam permainan saya, saya mengambil langkah lebih jauh. Saya menerapkan fungsi smoothing ke waktu masuk. Dengan cara itu paku FPS besar tidak menyebabkan fisika melompat terlalu jauh, melainkan disimulasikan lebih cepat untuk satu atau dua frame.
Anda menyebutkan bahwa dengan laju tetap, fisika tidak akan disinkronkan dengan tampilan. Ini benar jika laju fisika target dekat dengan frame rate target. Lebih buruk lagi laju bingkai lebih besar dari tingkat fisika. Secara umum lebih baik menargetkan tingkat pembaruan fisika dua kali lipat dari FPS target Anda, jika Anda mampu.
Jika Anda tidak mampu membayar laju pembaruan fisika yang besar, pertimbangkan untuk menginterpolasi posisi grafik di antara frame untuk membuat gambar yang digambar tampak bergerak lebih lancar daripada fisika yang sebenarnya bergerak.
sumber
Saya pikir sebenarnya ada 3 opsi, tetapi Anda hanya mencantumkannya 2:
Pilihan 1
Tidak melakukan apapun. Coba perbarui dan render pada interval tertentu, misalnya 60 kali per detik. Jika tertinggal, biarkan dan jangan khawatir. Gim akan melambat menjadi gerakan lambat jika CPU tidak dapat mengimbangi gim Anda. Opsi ini tidak akan berfungsi sama sekali untuk game multi-pengguna real-time, tetapi tidak masalah untuk game pemain tunggal dan telah berhasil digunakan di banyak game.
pilihan 2
Gunakan waktu delta antara setiap pembaruan untuk memvariasikan pergerakan objek. Besar dalam teori, terutama jika tidak ada dalam gim Anda yang mempercepat atau mengurangi kecepatan, tetapi hanya bergerak dengan kecepatan konstan. Dalam praktiknya, banyak pengembang menerapkan ini dengan buruk, dan itu dapat menyebabkan deteksi tabrakan dan fisika yang tidak konsisten. Tampaknya beberapa pengembang berpikir metode ini lebih mudah daripada itu. Jika Anda ingin menggunakan opsi ini, Anda perlu meningkatkan permainan Anda dan mengeluarkan beberapa matematika dan algoritma besar-besaran, misalnya menggunakan integrator fisika Verlet (bukan Euler standar yang digunakan kebanyakan orang) dan menggunakan sinar untuk deteksi tabrakan daripada pemeriksaan jarak Pythagoras sederhana. Saya mengajukan pertanyaan tentang ini di Stack Overflow beberapa waktu lalu dan mendapat beberapa jawaban:
https://stackoverflow.com/questions/153507/calculate-the-position-of-an-accelerating-body-after-a-certain-time
Opsi 3
Gunakan pendekatan "perbaiki langkah waktu" Gaffer Anda. Perbarui game dalam langkah-langkah tetap seperti pada opsi 1, tetapi lakukan beberapa kali per frame yang diberikan - berdasarkan berapa banyak waktu yang telah berlalu - sehingga logika game tetap sesuai dengan waktu nyata, sambil tetap dalam langkah-langkah terpisah. Dengan cara ini, mudah untuk mengimplementasikan logika game seperti integrator Euler dan deteksi tabrakan sederhana masih berfungsi. Anda juga memiliki opsi untuk menginterpolasi animasi grafis berdasarkan waktu delta, tetapi ini hanya untuk efek visual, dan tidak ada yang memengaruhi logika permainan inti Anda. Anda berpotensi mendapat masalah jika pembaruan Anda sangat intensif - jika pembaruan itu ketinggalan, Anda akan membutuhkan lebih banyak dan lebih banyak lagi untuk mengikutinya, berpotensi membuat gim Anda semakin tidak responsif.
Secara pribadi, saya suka Opsi 1 ketika saya bisa lolos dan Opsi 3 ketika saya perlu menyinkronkan ke waktu nyata. Saya menghargai bahwa Opsi 2 dapat menjadi opsi yang baik ketika Anda tahu apa yang Anda lakukan, tetapi saya tahu keterbatasan saya cukup baik untuk menjauh dari itu.
sumber
Saya sangat suka cara Kerangka XNA mengimplementasikan langkah waktu yang tetap. Jika panggilan draw yang diberikan memakan waktu terlalu lama, itu akan memanggil pembaruan berulang kali sampai "menyusul". Shawn Hargreaves menjelaskannya di sini:
http://blogs.msdn.com/b/shawnhar/archive/2007/11/23/game-timing-in-xna-game-studio-2-0.aspx
Pro terbesar menurut saya untuk ini adalah yang Anda sebutkan, yang membuat semua perhitungan kode permainan Anda jauh lebih mudah karena Anda tidak harus memasukkan variabel waktu di semua tempat.
Catatan: xna mendukung timestep variabel juga, itu hanya pengaturan.
sumber
Ada opsi lain - memutus pembaruan Game dan pembaruan fisika. Mencoba menyesuaikan mesin fisika dengan timestep game menyebabkan masalah jika Anda memperbaiki timestep Anda (masalah pemintalan di luar kendali karena integrasi membutuhkan lebih banyak waktu yang membutuhkan lebih banyak waktu yang membutuhkan lebih banyak waktu), atau buat variabel dan dapatkan fisika yang buruk.
Solusi yang saya lihat banyak adalah menjalankan fisika pada stempel waktu tetap, pada utas yang berbeda (pada inti yang berbeda). Gim menginterpolasi atau mengekstrapolasi mengingat dua frame valid terbaru yang bisa diambilnya. Interpolasi menambahkan beberapa kelambatan, ekstrapolasi menambahkan beberapa ketidakpastian, tetapi fisika Anda akan stabil dan tidak membuat timestep Anda lepas kendali.
Ini bukan hal sepele untuk diterapkan, tetapi mungkin membuktikan sendiri bukti di masa depan.
sumber
Secara pribadi, saya menggunakan variasi variabel waktu-langkah (yang merupakan semacam hibrida tetap dan variabel saya pikir). Saya menekankan menguji sistem pengaturan waktu ini dalam beberapa cara, dan saya menemukan diri saya menggunakannya untuk banyak proyek. Apakah saya merekomendasikannya untuk semuanya? Mungkin tidak.
Loop game saya menghitung jumlah frame yang akan diperbarui (sebut saja F ini), dan kemudian lakukan pembaruan logika F diskrit. Setiap pembaruan logika mengasumsikan satuan waktu yang konstan (yang sering 1/100 detik dalam game saya). Setiap pembaruan dilakukan secara berurutan sampai semua pembaruan logika diskrit F dilakukan.
Mengapa pembaruan diskrit dalam langkah-langkah logika? Nah, jika Anda mencoba dan menggunakan langkah berkelanjutan, dan tiba-tiba Anda memiliki gangguan fisika karena kecepatan dan jarak yang dihitung untuk bepergian dikalikan dengan nilai F. yang sangat besar
Implementasi yang buruk dari ini hanya akan melakukan F = waktu sekarang - pembaruan waktu bingkai terakhir. Tetapi jika perhitungan terlalu jauh di belakang (kadang-kadang karena keadaan di luar kendali Anda seperti proses lain mencuri waktu CPU), Anda akan dengan cepat melihat melewatkan yang mengerikan. Dengan cepat, FPS stabil yang Anda coba pertahankan menjadi SPF.
Dalam game saya, saya mengizinkan perlambatan "smooth" (semacam) untuk membatasi jumlah catchup logika yang harus dimungkinkan antara dua draw. Saya melakukan ini dengan menjepit: F = min (F, MAX_FRAME_DELTA) yang biasanya memiliki MAX_FRAME_DELTA = 2/100 * s atau 3/100 * s. Jadi, alih-alih melewatkan frame saat terlalu jauh di belakang logika game, buang frame loss besar-besaran (yang memperlambat segalanya), pulihkan beberapa frame, gambar, dan coba lagi.
Dengan melakukan ini, saya juga memastikan bahwa kontrol pemain tetap sinkron lebih dekat dengan apa yang sebenarnya ditampilkan di layar.
Pseudocode produk akhir adalah sesuatu seperti ini (delta adalah F yang disebutkan sebelumnya):
Pembaruan semacam ini tidak cocok untuk semuanya, tetapi untuk permainan gaya arcade, saya lebih suka melihat permainan melambat karena ada banyak hal yang terjadi daripada bingkai ketinggalan dan kehilangan kontrol pemain. Saya juga lebih suka ini dengan pendekatan langkah variabel-waktu lainnya yang akhirnya memiliki gangguan yang tidak dapat diproduksi kembali yang disebabkan oleh kehilangan bingkai.
sumber
Solusi ini tidak berlaku untuk semuanya, tetapi ada tingkat lain dari timestep variabel - timestep variabel untuk setiap objek di dunia.
Ini tampaknya rumit, dan memang bisa, tetapi anggap itu sebagai pemodelan game Anda sebagai simulasi peristiwa diskrit. Setiap gerakan pemain dapat direpresentasikan sebagai peristiwa yang dimulai saat gerakan dimulai, dan berakhir saat gerakan berakhir. Jika ada interaksi yang mengharuskan acara dipecah (tabrakan misalnya) acara dibatalkan dan acara lain didorong ke antrian acara (yang mungkin merupakan antrian prioritas diurutkan berdasarkan waktu akhir acara).
Rendering sepenuhnya terlepas dari antrian acara. Mesin display menginterpolasi poin antara waktu mulai / akhir acara sebagaimana diperlukan, dan dapat seakurat atau serobak dalam perkiraan ini sebagaimana diperlukan.
Untuk melihat implementasi rumit dari model ini, lihat EXOFLIGHT simulator ruang . Ini menggunakan model eksekusi yang berbeda dari sebagian besar simulator penerbangan - model berbasis acara, bukan model tradisional time-slice. Loop utama dasar dari jenis simulasi ini terlihat seperti ini, dalam pseudo-code:
Alasan utama untuk menggunakan satu dalam simulator ruang adalah perlunya menyediakan percepatan waktu sewenang-wenang tanpa kehilangan keakuratan. Beberapa misi dalam EXOFLIGHT mungkin membutuhkan waktu bertahun-tahun untuk menyelesaikannya, dan bahkan opsi akselerasi 32x saja tidak cukup. Anda membutuhkan akselerasi 1.000.000 x lebih untuk sim yang dapat digunakan, yang sulit dilakukan dalam model slice waktu. Dengan model berbasis peristiwa, kami mendapatkan nilai waktu sewenang-wenang, dari 1 s = 7 ms hingga 1 s = 1 thn.
Mengubah laju waktu tidak mengubah perilaku sim, yang merupakan fitur penting. Jika tidak ada cukup daya CPU yang tersedia untuk menjalankan simulator pada kecepatan yang diinginkan, acara akan menumpuk dan kami mungkin membatasi menyegarkan UI sampai antrian acara dihapus. Demikian pula, kita dapat mempercepat sim seperti yang kita inginkan dan pastikan kita tidak membuang-buang CPU atau mengorbankan akurasi.
Jadi kesimpulannya: Kita dapat memodelkan satu kendaraan dalam orbit yang panjang dan santai (menggunakan integrasi Runge-Kutta) dan kendaraan lain secara bersamaan memantul di tanah - kedua kendaraan akan disimulasikan pada akurasi yang sesuai karena kita tidak memiliki catatan waktu global.
Cons: Kompleksitas, dan kurangnya mesin fisika off-the-shelf yang mendukung model ini :)
sumber
Langkah waktu yang diperbaiki bermanfaat ketika mempertimbangkan keakuratan titik mengambang akun dan untuk membuat pembaruan konsisten.
Ini adalah sepotong kode sederhana sehingga akan berguna untuk mencobanya dan melihat apakah itu berfungsi untuk gim Anda.
Masalah utama dengan menggunakan langkah waktu tetap adalah bahwa pemain dengan komputer cepat tidak akan dapat memanfaatkan kecepatan. Render pada 100fps saat gim diperbarui hanya pada 30fps sama seperti rendering pada 30fps.
Meskipun demikian, dimungkinkan untuk menggunakan lebih dari satu langkah waktu yang tetap. 60fps dapat digunakan untuk memperbarui objek sepele (seperti sprite UI atau animasi) dan 30fps untuk memperbarui sistem non-sepele (seperti fisika dan) dan bahkan timer yang lebih lambat untuk dilakukan di belakang manajemen layar seperti menghapus objek yang tidak digunakan, sumber daya dll.
sumber
Di atas apa yang sudah Anda nyatakan, mungkin akan terasa seperti keinginan Anda untuk memiliki gim. Kecuali Anda dapat menjamin bahwa Anda akan selalu memiliki frame rate yang konstan maka Anda cenderung mengalami pelambatan di suatu tempat dan langkah-langkah waktu yang tetap dan variabel akan terlihat sangat berbeda. Fixed akan memiliki efek permainan Anda bergerak lambat untuk sementara waktu, yang kadang-kadang bisa menjadi efek yang diinginkan (lihat penembak gaya sekolah lama seperti Ikaruga di mana ledakan besar menyebabkan perlambatan setelah mengalahkan bos). Stempel waktu variabel akan membuat segala sesuatunya bergerak dengan kecepatan yang benar dalam hal waktu tetapi Anda mungkin melihat perubahan mendadak pada posisi dll. Yang dapat menyulitkan pemain untuk melakukan tindakan secara akurat.
Saya tidak dapat benar-benar melihat bahwa langkah waktu Tetap akan membuat segalanya lebih mudah melalui jaringan, mereka semua akan sedikit tidak sinkron untuk memulai dan memperlambat pada satu mesin tetapi tidak yang lain akan mendorong hal-hal lebih tidak sinkron.
Saya selalu condong ke pendekatan variabel secara pribadi tetapi artikel-artikel itu memiliki beberapa hal menarik untuk dipikirkan. Saya masih menemukan langkah-langkah tetap cukup umum, terutama pada konsol di mana orang berpikir framerate menjadi 60fps konstan dibandingkan dengan tingkat yang sangat tinggi yang dapat dicapai pada PC.
sumber
Gunakan pendekatan "perbaiki langkah waktu" Gaffer Anda. Perbarui game dalam langkah-langkah tetap seperti pada opsi 1, tetapi lakukan beberapa kali per frame yang diberikan - berdasarkan berapa banyak waktu yang telah berlalu - sehingga logika game tetap sesuai dengan waktu nyata, sambil tetap dalam langkah-langkah terpisah. Dengan cara ini, mudah untuk mengimplementasikan logika game seperti integrator Euler dan deteksi tabrakan sederhana masih berfungsi. Anda juga memiliki opsi untuk menginterpolasi animasi grafis berdasarkan waktu delta, tetapi ini hanya untuk efek visual, dan tidak ada yang memengaruhi logika permainan inti Anda. Anda berpotensi mendapat masalah jika pembaruan Anda sangat intensif - jika pembaruan itu ketinggalan, Anda akan membutuhkan lebih banyak dan lebih banyak lagi untuk mengikutinya, berpotensi membuat gim Anda semakin tidak responsif.
Secara pribadi, saya suka Opsi 1 ketika saya bisa lolos dan Opsi 3 ketika saya perlu menyinkronkan ke waktu nyata. Saya menghargai bahwa Opsi 2 bisa menjadi pilihan yang baik ketika Anda tahu apa yang Anda lakukan, tetapi saya tahu keterbatasan saya cukup baik untuk menjauh dari itu
sumber
Saya telah menemukan bahwa stempel waktu tetap yang disinkronkan ke 60fps memberikan animasi cermin yang halus. Ini sangat penting untuk aplikasi VR. Ada lagi yang secara fisik memuakkan.
Cap waktu variabel tidak cocok untuk VR. Lihat beberapa contoh Unity VR yang menggunakan langkah waktu variabel. Itu tidak menyenangkan.
Aturannya adalah jika game 3D Anda mulus dalam mode VR, itu akan sangat baik dalam mode non-VR.
Bandingkan kedua (aplikasi Karton VR) ini
(Tanda waktu variabel)
(Tanda waktu tetap)
Game Anda harus multithreaded untuk mencapai timestep / framerate yang konsisten. Fisika, UI, dan rendering harus dipisahkan menjadi utas khusus. Ini adalah PITA yang mengerikan untuk menyinkronkannya, tetapi hasilnya adalah rendering mirror yang Anda inginkan (esp. Untuk VR).
Game mobile khususnya. menantang karena CPU dan GPU yang tertanam memiliki kinerja yang terbatas. Gunakan GLSL (gaul) hemat untuk membongkar sebanyak mungkin pekerjaan dari CPU. Waspadai daripada melewatkan parameter ke GPU menghabiskan sumber daya bus.
Selalu pertahankan framerate Anda ditampilkan selama pengembangan. Gim sebenarnya adalah membuatnya tetap pada 60fps. Ini adalah tingkat sinkronisasi asli untuk sebagian besar layar dan juga untuk sebagian besar bola mata.
Kerangka kerja yang Anda gunakan harus dapat memberi tahu Anda tentang permintaan sinkronisasi, atau menggunakan timer. Jangan masukkan penundaan tidur / tunggu untuk mencapai ini - bahkan sedikit variasi terlihat.
sumber
Langkah waktu variabel adalah untuk prosedur yang harus dijalankan sesering mungkin: Membuat siklus, penanganan acara, hal-hal jaringan dll.
Langkah waktu tetap adalah saat Anda membutuhkan sesuatu yang dapat diprediksi dan stabil. Ini termasuk, tetapi tidak terbatas pada deteksi fisika & tabrakan.
Dalam istilah praktis, fisika dan deteksi tabrakan harus dipisahkan dari yang lainnya, pada langkah waktunya sendiri. Alasan untuk melakukan prosedur seperti ini pada langkah waktu yang tetap kecil, adalah untuk membuatnya akurat. Besarnya impuls sangat tergantung pada waktu, dan jika intervalnya terlalu besar, simulasi menjadi tidak stabil, dan hal-hal gila terjadi seperti bola memantul melewati tanah, atau memantul keluar dari dunia game, yang keduanya tidak diinginkan.
Segala sesuatu yang lain dapat berjalan pada langkah waktu variabel (meskipun secara profesional, itu sering kali merupakan Ide yang baik untuk memungkinkan penguncian render ke langkah waktu yang tetap). Agar mesin game responsif, hal-hal seperti pesan jaringan dan input pengguna harus ditangani sesegera mungkin, yang berarti bahwa interval antara polling idealnya harus sesingkat mungkin. Ini umumnya berarti variabel.
Segala sesuatu yang lain dapat ditangani secara tidak sinkron, menjadikan waktu sebagai titik diperdebatkan.
sumber