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?
sumber
Jawaban:
Satu-satunya hal untuk dikatakan adalah 2D, isometrik, 3D, semuanya sama dalam masalah ini. Karena Anda melihat banyak contoh 3D dan Anda hanya menggunakan sistem input terbatas oktan 2D dengan kecepatan sesaat tidak berarti Anda dapat membuang prinsip-prinsip jaringan yang telah berkembang selama 20+ tahun terakhir.
Prinsip-prinsip desain akan terkutuk saat permainan dikompromikan!
Dengan membuang sebelumnya dan saat ini Anda membuang beberapa informasi yang dapat menyelesaikan masalah Anda. Untuk data tersebut saya akan menambahkan waktu-perangko dan menghitung lag sehingga ekstrapolasi dapat memprediksi dengan lebih baik di mana pemain akan berada dan interpolasi dapat lebih baik memuluskan perubahan kecepatan dari waktu ke waktu.
Di atas adalah alasan besar mengapa server tampaknya mengirimkan banyak informasi negara dan tidak mengontrol input. Alasan besar lainnya didasarkan pada protokol apa yang Anda gunakan. UDP dengan paket loss yang diterima dan pengiriman tidak sesuai pesanan? TCP dengan pengiriman yang terjamin dan coba lagi? Dengan protokol apa pun Anda akan mendapatkan paket pada waktu yang aneh, tertunda atau bertumpuk satu sama lain dalam kesibukan. Semua paket aneh itu perlu masuk ke dalam konteks sehingga klien dapat mengetahui apa yang terjadi.
Akhirnya, meskipun input Anda sangat terbatas pada 8 arah, perubahan yang sebenarnya dapat terjadi kapan saja - menerapkan siklus 250ms hanya akan membuat pemain frustrasi. 30 pemain bukan masalah besar untuk ditangani server mana pun. Jika Anda berbicara tentang ribuan ... bahkan grup-grup itu terbagi menjadi beberapa boxen sehingga masing-masing server hanya membawa beban yang masuk akal.
Apakah Anda pernah membuat profil mesin fisika seperti Havok atau Bullet berjalan? Mereka sangat dioptimalkan dan sangat, sangat cepat. Anda mungkin jatuh ke dalam perangkap dengan asumsi operasi ABC akan lambat dan mengoptimalkan sesuatu yang tidak membutuhkannya.
sumber
Jadi server Anda pada dasarnya adalah "wasit"? Dalam hal ini, saya percaya bahwa segala sesuatu di klien Anda harus bersifat deterministik; Anda perlu memastikan bahwa semua yang ada di setiap klien akan selalu memberikan hasil yang sama.
Untuk pertanyaan pertama Anda, setelah pemain lokal menerima arah pemain lain, selain tidak mampu melemahkan pergerakannya dari waktu ke waktu dan menerapkan tabrakan, saya tidak melihat bagaimana Anda bisa memprediksi ke arah mana pemain akan beralih berikutnya, terutama dalam suatu 8 arah lingkungan.
Ketika Anda menerima pembaruan "posisi asli" dari masing-masing pemain (yang mungkin Anda bisa mencoba mengejutkannya di server) ya Anda perlu menginterpolasi posisi dan arah pemain. Jika posisi "tebak" sangat salah (yaitu pemain benar-benar mengubah arah tepat setelah paket arah terakhir dikirim) Anda akan memiliki celah besar. Ini berarti bahwa pemain melompat posisi, atau Anda dapat menginterpolasi ke posisi menebak berikutnya . Ini akan memberikan interpolasi yang lebih lancar dari waktu ke waktu.
Ketika entitas bertabrakan, jika Anda dapat membuat sistem determinis, setiap pemain dapat mensimulasikan tabrakan secara lokal, dan hasilnya tidak boleh terlalu jauh dari kenyataan. Setiap mesin lokal harus mensimulasikan tabrakan untuk kedua pemain, dalam hal ini memastikan bahwa keadaan akhir akan non-blocking dan dapat diterima.
Untuk sisi server, server wasit masih dapat melakukan perhitungan sederhana untuk memeriksa misalnya kecepatan pemain dalam waktu singkat untuk digunakan sebagai mekanisme anti-cheat sederhana. Jika Anda mengulang pemantauan setiap pemain lebih dari 1 pada satu waktu, deteksi cheat Anda akan scalable, hanya saja akan lebih lama untuk menemukan curang.
sumber
Tidak bisakah Anda memasukkan kecepatan dalam keadaan Anda mengubah pesan dan menggunakannya untuk memprediksi gerakan? mis. anggap kecepatan tidak berubah sampai Anda mendapatkan pesan yang mengatakan itu berubah? Saya pikir Anda sudah mengirim posisi, jadi jika sesuatu "melampaui" karena ini Anda tetap memiliki posisi yang benar dari pembaruan berikutnya. Kemudian Anda dapat melangkah posisi selama pembaruan seperti yang Anda lakukan menggunakan kecepatan dari pesan terakhir, dan menimpa posisi setiap kali pesan diterima dengan posisi baru. Ini juga berarti bahwa jika posisi tidak berubah, tetapi kecepatan Anda perlu mengirim pesan (jika itu bahkan merupakan kasus yang valid dalam game Anda), tetapi itu tidak akan banyak mempengaruhi penggunaan bandwidth Anda, jika sama sekali.
Interpolasi seharusnya tidak menjadi masalah di sini, yaitu misalnya ketika Anda tahu di mana sesuatu akan terjadi di masa depan, apakah Anda memilikinya, metode apa yang Anda gunakan, dll. Apakah Anda bingung dengan ekstrapolasi mungkin? (yang saya jelaskan adalah satu, sederhana, pendekatan)
sumber
Pertanyaan pertama saya adalah: Apa yang salah dengan menggunakan model di mana server memiliki otoritas? Mengapa penting apakah lingkungannya 2D atau 3D? Itu akan membuat perlindungan cheat Anda jauh lebih mudah jika server Anda otoritatif.
Saat melakukan prediksi, perlu untuk mempertahankan beberapa status (atau setidaknya delta) pada klien sehingga ketika status otoritatif / delta diterima dari server, dapat dibandingkan dengan yang dimiliki klien dan Anda dapat membuat yang diperlukan koreksi. Idenya adalah untuk menjaga sebanyak mungkin deterministik untuk meminimalkan jumlah koreksi yang diperlukan. Jika Anda tidak mempertahankan status sebelumnya, Anda tidak bisa tahu apakah sesuatu yang berbeda terjadi di server.
Mengapa Anda perlu interpolasi? Server otoritatif harus menimpa setiap gerakan yang salah.
Ini adalah situasi di mana akan ada konflik antara server dan klien dan itulah sebabnya Anda perlu mempertahankan status pada klien sehingga server dapat memperbaiki kesalahan.
Maaf untuk jawaban cepat, saya harus pergi. Baca artikel ini , ia menyebutkan penembak tetapi harus bekerja untuk game apa pun yang membutuhkan jaringan waktu nyata.
sumber