Jalankan simulasi fisika pada klien dan server?


13

Saya menerapkan klon asteroid multipemain untuk belajar tentang arsitektur jaringan klien / server dalam permainan. Saya telah menghabiskan waktu membaca publikasi GafferOnGames dan Valve tentang teknologi klien / server mereka. Saya mengalami masalah dengan dua konsep.

  1. Saat ini saya memiliki server permainan otoritatif yang mensimulasikan fisika dengan box2d dan mengirimkan keadaan dunia kepada klien sekitar 20 kali per detik. Setiap klien melacak beberapa snapshot terakhir yang diterima dan lerps antara dua negara untuk memperlancar pergerakan sprite. Namun tidak semulus itu. Bisa mulus untuk sementara waktu, lalu sedikit tersentak-sentak, lalu kembali ke halus, dll. Saya telah mencoba TCP dan UDP, keduanya hampir sama. Adakah yang tahu apa masalah saya? (Catatan: Saya menerapkan ini untuk pemain tunggal terlebih dahulu, dan gerakan sprite sangat halus pada 60fps saat memperbarui dunia fisika hanya 20 kali per detik).

  2. Untuk menyelesaikan masalah pertama saya pikir mungkin klien harus menjalankan simulasi box2d juga dan hanya memperbarui posisi sprite-nya untuk mencocokkan snapshot server ketika mereka tidak cocok. Saya pikir ini mungkin lebih lancar karena implementasi pemain tunggal saya lancar. Apakah ini ide yang bagus?

    Bahkan jika itu tidak akan memperbaiki masalah di atas, apakah perlu untuk prediksi sisi klien? Misalnya, jika seorang pemain mencoba untuk memindahkan kapalnya, bagaimana mereka akan tahu jika mereka menabrak asteroid, dinding, atau kapal musuh tanpa simulasi fisika? Sepertinya kapal mereka akan terlihat melewati objek yang harus bertabrakan dengan mereka sebelum mereka menerima snapshot dari server yang mengatakan bahwa mereka mengenai objek tersebut.

Terima kasih!

Jawaban:


10

Jalankan simulasi pada klien dan server. Ada lagi yang memiliki latensi terlalu lama. Anda harus yakin bahwa simulasi cocok dengan memasukkan objek dalam urutan yang sama, menggunakan langkah waktu yang tetap dan menghindari perbandingan pointer. Saya belum mencoba ini dengan Box2D tetapi secara umum dimungkinkan untuk mencapai perilaku yang sama pada semua mesin dalam simulasi fisika. Semua matematika biasanya didasarkan pada pelampung IEEE 754 binary32 dan perilakunya didefinisikan secara ketat untuk operasi seperti +-*/beberapa nama. Anda harus berhati-hati sin,cosdan suka suka, karena mereka dapat berbeda antara runtimes (ini sangat penting ketika mengembangkan untuk beberapa platform). Pastikan juga Anda menggunakan pengaturan ketat untuk optimisasi float di kompiler Anda. Anda masih dapat menyinkronkan objek dengan mengirimkan keadaan objek secara berkala dari server. Jangan memperbarui kecuali perbedaannya lebih besar dari ambang untuk menghindari kegagapan yang tidak perlu.

Salah satu masalah yang muncul dalam pikiran adalah penciptaan objek baru dan bagaimana hal itu akan mengubah simulasi antara klien. Salah satu cara untuk memperbaikinya adalah membiarkan server membuat semua objek. Jika langkah waktu saat ini adalah t, server akan menjadwalkan objek yang akan ditambahkan t+d. Dengan demikian, daftar objek baru, dengan objek yang akan ditambahkan dan kapan ditambahkan, dapat dipertahankan di semua klien dan diperbarui oleh server jauh sebelumnya. Jika dcukup besar, Anda meminimalkan risiko hasil yang berbeda. Jika Anda benar-benar tidak dapat menangani perbedaan, Anda dapat memaksa klien untuk menunggu informasi tentang objek baru untuk langkah waktu tertentu sebelum mensimulasikan langkah waktu itu.


Terimakasih atas tanggapan Anda. Saya tidak berpikir box2d dijamin untuk menghasilkan hasil yang sama di berbagai CPU, yang akan menjadi skenario bagi kami karena kami sedang menulis game desktop. Saya berharap perbedaannya kecil dan mudah diperbaiki dengan pembaruan berkala dari server yang berwenang, tetapi saya belum pernah mencobanya.
Venesectrix

Erin Catto berpikir, bahwa mencoba untuk menjaga seluruh keadaan beberapa dunia Box2D tetap sinkron adalah pertempuran yang kalah ( box2d.org/forum/viewtopic.php?f=3&t=8462 )
Pavel

Pernyataan "perilaku IEEE 754 binary32 mengapung [..] secara ketat didefinisikan untuk operasi seperti +-*/" benar-benar salah. Semua operasi di IEEE-754 dapat bervariasi berdasarkan pada implementasinya. Lihat di sini dan di sini untuk info lebih lanjut.
BlueRaja - Danny Pflughoeft

1
Tidak. Itu sepenuhnya benar. Masalah yang dijelaskan tautan Anda terkait dengan mode fpu x87 yang berbeda dan implementasi transendental. IEEE 754 binary32 adalah didefinisikan secara ketat untuk operasi dasar. Terserah Anda untuk mengatur mode yang benar dan menggunakan instruksi yang tepat sehingga standar diikuti. Cukup menggunakan instruksi SSE dan bukan fpu x87 banyak membantu.
rasmus

4

Ini mungkin tidak terlihat begitu baik karena interpolasi di antara mereka bergantung pada selalu memiliki set data berikutnya untuk diinterpolasi. Ini berarti bahwa, jika ada lonjakan jeda pendek, semuanya harus menunggu untuk mengejar ketinggalan.

Ada artikel lama di GameDev tentang menggunakan splines kubik untuk memprediksi posisi objek melewati titik di mana Anda terakhir memiliki data untuk itu. Yang kemudian Anda lakukan adalah menggunakan posisi itu dan kemudian menyesuaikan spline ketika Anda mendapatkan data baru untuk memperhitungkan posisi baru itu. Ini juga mungkin jauh lebih murah daripada menjalankan simulasi fisika kedua, dan itu berarti Anda tidak harus memutuskan siapa yang Anda percayai, karena Anda telah secara eksplisit mengimplementasikan klien yang mengada-ada. :)


Ini bisa jadi masalahnya. Apa yang saya coba lakukan adalah menunda sampai saya menerima 3 snapshot dari server. Pada titik I lerp dari shot 1 ke shot 2. Kemudian dari shot 2 ke shot 3. Jika suatu saat saya ketinggalan paket saya bisa lerp dari 1 ke 3, daripada 1 ke 2, jika itu masuk akal. Saya mungkin belum mengimplementasikan ini dengan benar. Terima kasih atas tautannya ke artikel!
Venesectrix

1

Saya sendiri sudah melakukan beberapa hal yang serupa, dan saya menjalankan Box2D hanya pada klien. Cara saya melakukannya adalah membiarkan klien menjalankan simulasi sendiri dengan cukup banyak, mengirimkan kecepatan saat ini (dan rotasi) pada setiap paket sinkronisasi ke server. Server kemudian mengirimkan informasi ini ke pemain lain, yang mengatur kecepatan yang baru diterima ke entitas yang direplikasi. Itu sangat lancar, tanpa ada perbedaan mencolok antara klien.

Tentu saja, masalahnya di sini adalah bahwa tidak ada kontrol terpusat atas entitas, tapi saya pikir itu bisa dilakukan di sisi server juga dengan melakukan simulasi fisika sisi-server juga.


Terima kasih atas masukan Anda. Kami akan memerlukan kontrol terpusat untuk mencegah kecurangan, jadi kami harus memiliki server yang menjalankan simulasi setidaknya untuk mengetahui apakah apa yang klien katakan sedang mereka lakukan mungkin atau tidak.
Venesectrix

1

Saya pribadi lebih suka menjalankan simulasi hanya di server dan menyiarkannya perubahan pada kecepatan linear / sudut / percepatan objek yang terlibat setiap kali mereka terjadi. Itu adalah, ketika suatu objek tertentu, untuk alasan apa pun, mengubah sifat fisiknya (seperti kecepatan dan percepatan yang disebutkan di atas), perubahan spesifik ini akan dikirim dari server ke klien, dan klien akan mengubah sisi itu dari objek tersebut. data objek sesuai.

Keuntungannya daripada implementasi Anda saat ini adalah bahwa itu akan membatalkan perlunya interpolasi sisi klien dan akan menghasilkan perilaku yang sangat setia pada objek. Masalahnya adalah bahwa metode ini sangat sangat rentan terhadap latensi, yang menjadi masalah yang sangat besar ketika para pemain secara geografis terlalu jauh satu sama lain.

Sedangkan untuk pertanyaan 1, saya katakan masalahnya adalah fluktuasi pada latensi, karena tidak ada jaminan mutlak bahwa akan ada interval 20 detik yang tepat antara setiap penerima snapshot. Biarkan saya menggambarkan (menjadi "t" waktu yang diukur dalam milidetik):

1) Pada t = 20 sejak awal permainan, klien menerima snapshot dan melakukan interpolasi berhasil dan lancar.

2) Pada t = 40, ada latensi antara server dan klien, dan potret yang terjadi hanya benar-benar sampai pada t = 41.

3) Pada t = 60, server mengirim snapshot lain, tetapi satu detik simulasi sia-sia di sisi klien karena latensi. Jika snapshot tiba pada t = 60, klien tidak akan melakukan interpolasi dari 40 dan 60 instance, tetapi sebenarnya dari instance 41 hingga 60, menghasilkan perilaku yang berbeda. Ketidakaktifan ini mungkin menjadi penyebab "jerkiness" akhirnya.

Sedangkan untuk pertanyaan 2, ide Anda mungkin berfungsi jika Anda mengimplementasikan sesuatu yang secara efisien akan melacak apakah setiap objek benar-benar disinkronkan dengan server-klien tanpa harus mengirim paket setiap frame yang menginformasikan posisi objek. Bahkan jika Anda melakukannya pada interval diskrit, Anda tidak hanya akan berjalan pada masalah yang sama dari pertanyaan 1, tetapi juga memiliki jumlah data yang terlalu besar untuk ditransfer (yang merupakan hal yang buruk).


Saya tidak yakin saya mengikuti apa yang Anda katakan di paragraf pertama Anda. Jika simulasi hanya berjalan di server dan Anda hanya menyiarkan perubahan kecepatan / akselerasi, lalu bagaimana klien tahu di mana sprite harus diambil? Klien harus mensimulasikan objek berdasarkan kecepatan / akselerasi yang diterima untuk menggambar mereka dengan benar. Saya pikir Anda mungkin benar tentang menerima snapshot pada interval selain apa yang saya harapkan. Adakah cara mengatasinya?
Venesectrix

Klien mengetahui posisi awal dan saat ini, kecepatan dan percepatan objek, dan akan memperbarui posisi yang dianggapnya objek (terlepas dari server). Server pada akhirnya akan mengubah properti tersebut pada klien melalui pesan, karena itu adalah server yang melakukan deteksi fisika dan tabrakan (yang terikat untuk mengubah kecepatan / percepatan dan arah objek yang diberikan cepat atau lambat)
UBSophung
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.