Saya sedang mengerjakan game 2D isometrik dengan multiplayer skala sedang, sekitar 20-30 pemain terhubung sekaligus ke server persisten. Saya mengalami beberapa kesulitan untuk mendapatkan implementasi prediksi pergerakan yang baik.
Fisika / Gerakan
Gim ini tidak memiliki implementasi fisika sejati, tetapi menggunakan prinsip-prinsip dasar untuk mengimplementasikan gerakan. Alih-alih input polling yang terus-menerus, perubahan status (mis. Mouse / turun / atas / memindahkan peristiwa) digunakan untuk mengubah status entitas karakter yang dikontrol pemain. Arah pemain (yaitu / utara-timur) dikombinasikan dengan kecepatan konstan dan berubah menjadi vektor 3D sejati - kecepatan entitas.
Di loop permainan utama, "Pembaruan" disebut sebelum "Draw". Logika pembaruan memicu "tugas pembaruan fisika" yang melacak semua entitas dengan kecepatan non-nol menggunakan integrasi yang sangat mendasar untuk mengubah posisi entitas. Sebagai contoh: entitas.Posisi + = entitas.Velocity.Scale (ElapsedTime.Seconds) (di mana "Detik" adalah nilai titik mengambang, tetapi pendekatan yang sama akan bekerja untuk nilai integer milidetik).
Poin kuncinya adalah bahwa tidak ada interpolasi digunakan untuk gerakan - mesin fisika dasar tidak memiliki konsep "keadaan sebelumnya" atau "keadaan saat ini", hanya posisi dan kecepatan.
Sebutkan Perubahan dan Perbarui Paket
Ketika kecepatan entitas karakter pemain mengendalikan perubahan, paket "pindahkan avatar" dikirim ke server yang berisi jenis tindakan entitas (berdiri, berjalan, jalankan), arah (timur laut), dan posisi saat ini. Ini berbeda dari cara kerja game orang pertama 3D. Dalam game 3D, kecepatan (arah) dapat mengubah bingkai ke bingkai saat pemain bergerak. Mengirim setiap perubahan status akan secara efektif mengirimkan paket per frame, yang akan terlalu mahal. Sebagai gantinya, game 3D tampaknya mengabaikan perubahan status dan mengirim paket "pembaruan negara" pada interval tetap - misalnya, setiap 80-150 ms.
Karena pembaruan kecepatan dan arah terjadi lebih jarang di game saya, saya bisa lolos dengan mengirim setiap perubahan status. Meskipun semua simulasi fisika terjadi pada kecepatan yang sama dan bersifat deterministik, latensi masih menjadi masalah. Untuk alasan itu, saya mengirimkan paket pembaruan posisi rutin (mirip dengan game 3D) tetapi jauh lebih jarang - sekarang setiap 250ms, tetapi saya curiga dengan prediksi yang baik saya dapat dengan mudah meningkatkannya ke 500ms. Masalah terbesar adalah bahwa saya sekarang telah menyimpang dari norma - semua dokumentasi lain, panduan, dan sampel online mengirim pembaruan rutin dan interpolasi antara kedua negara. Tampaknya tidak kompatibel dengan arsitektur saya, dan saya perlu membuat algoritma prediksi pergerakan yang lebih baik yang lebih dekat dengan arsitektur "jaringan fisika" (sangat dasar).
Server kemudian menerima paket dan menentukan kecepatan pemain dari jenis gerakannya berdasarkan pada skrip (Apakah pemain dapat berlari? Dapatkan kecepatan lari pemain). Setelah memiliki kecepatan, ia menggabungkannya dengan arah untuk mendapatkan vektor - kecepatan entitas. Beberapa deteksi cheat dan validasi dasar terjadi, dan entitas di sisi server diperbarui dengan kecepatan, arah, dan posisi saat ini. Pelambatan dasar juga dilakukan untuk mencegah pemain membanjiri server dengan permintaan gerakan.
Setelah memperbarui entitasnya sendiri, server menyiarkan paket "pembaruan posisi avatar" ke semua pemain lain dalam jangkauan. Paket pembaruan posisi digunakan untuk memperbarui simulasi fisika sisi klien (keadaan dunia) dari klien jarak jauh dan melakukan prediksi dan kompensasi lag.
Prediksi dan Kompensasi Lag
Seperti disebutkan di atas, klien berwibawa untuk posisi mereka sendiri. Kecuali dalam kasus kecurangan atau anomali, avatar klien tidak akan pernah diposisikan ulang oleh server. Tidak diperlukan ekstrapolasi ("bergerak sekarang dan perbaiki nanti") untuk avatar klien - apa yang dilihat pemain itu benar. Namun, semacam ekstrapolasi atau interpolasi diperlukan untuk semua entitas jarak jauh yang bergerak. Beberapa jenis prediksi dan / atau kompensasi-lambat jelas diperlukan dalam mesin simulasi / fisika lokal klien.
Masalah
Saya telah berjuang dengan berbagai algoritma, dan memiliki sejumlah pertanyaan dan masalah:
Haruskah saya mengekstrapolasi, menginterpolasi, atau keduanya? "Perasaan" saya adalah bahwa saya harus menggunakan ekstrapolasi murni berdasarkan kecepatan. Perubahan status diterima oleh klien, klien menghitung kecepatan "prediksi" yang mengkompensasi kelambatan, dan sistem fisika reguler melakukan sisanya. Namun, rasanya bertentangan dengan semua kode sampel dan artikel lainnya - mereka semua tampaknya menyimpan sejumlah negara dan melakukan interpolasi tanpa mesin fisika.
Ketika sebuah paket tiba, saya telah mencoba menginterpolasi posisi paket dengan kecepatan paket selama periode waktu yang tetap (katakanlah, 200 ms). Saya kemudian mengambil perbedaan antara posisi interpolasi dan posisi "kesalahan" saat ini untuk menghitung vektor baru dan menempatkannya pada entitas alih-alih kecepatan yang dikirim. Namun, asumsinya adalah bahwa paket lain akan tiba dalam interval waktu itu, dan itu sangat sulit untuk "menebak" ketika paket berikutnya akan tiba - terutama karena mereka tidak semuanya tiba pada interval tetap (yaitu / perubahan negara juga). Apakah konsepnya cacat secara mendasar, atau apakah itu benar tetapi perlu beberapa perbaikan / penyesuaian?
Apa yang terjadi ketika pemain jarak jauh berhenti? Saya dapat segera menghentikan entitas, tetapi akan diposisikan di tempat yang "salah" hingga bergerak lagi. Jika saya memperkirakan vektor atau mencoba menginterpolasi, saya memiliki masalah karena saya tidak menyimpan keadaan sebelumnya - mesin fisika tidak memiliki cara untuk mengatakan "Anda harus berhenti setelah Anda mencapai posisi X". Itu hanya memahami kecepatan, tidak ada yang lebih kompleks. Saya enggan menambahkan informasi "paket gerakan negara" ke entitas atau mesin fisika, karena melanggar prinsip-prinsip desain dasar dan mengeluarkan kode jaringan di seluruh mesin permainan.
Apa yang harus terjadi ketika entitas bertabrakan? Ada tiga skenario - pemain pengendali bertabrakan secara lokal, dua entitas bertabrakan di server selama pembaruan posisi, atau pembaruan entitas jarak jauh bertabrakan pada klien lokal. Dalam semua kasus, saya tidak yakin bagaimana menangani tabrakan - selain dari menyontek, kedua negara "benar" tetapi pada periode waktu yang berbeda. Dalam kasus entitas jauh tidak masuk akal untuk menggambarnya berjalan melalui dinding, jadi saya melakukan deteksi tabrakan pada klien lokal dan membuatnya "berhenti". Berdasarkan poin # 2 di atas, saya dapat menghitung "vektor yang dikoreksi" yang terus-menerus mencoba untuk memindahkan entitas "melalui dinding" yang tidak akan pernah berhasil - avatar jarak jauh macet di sana sampai kesalahannya terlalu tinggi dan "terkunci" ke dalam posisi. Bagaimana permainan mengatasi ini?