Bagaimana cara menyinkronkan jam dalam game multi-pemain?

8

Saya memiliki 2 hingga 3 klien, yang dapat bertukar pesan melalui Apple Game Center.

Satu-satunya sinkronisasi yang saya butuhkan adalah: memulai permainan pada saat yang sama.

Saya kira ini melibatkan sinkronisasi jam. Bagaimana cara mencapai ini?

GameCoder
sumber
3
Jawaban singkatnya adalah 'kamu tidak bisa'. Keterlambatan yang tak terhindarkan (dan tidak konsisten) dalam komunikasi antara perangkat berarti bahwa bahkan jika satu perangkat mengatakan 'Saya percaya sekarang 12: 00: 00.00' maka dapat dengan mudah berada di mana saja dari 12: 00: 00.10 hingga 12:00:05 oleh waktu pesan itu diterima di tempat lain. Dalam model berbasis server Anda tidak bisa melakukan lebih baik daripada hanya meminta server Anda mengirim pesan 'Mulai permainan' ke klien pada saat yang sama.
Steven Stadnicki
Untung aku tidak butuh kesempurnaan. Bagaimana cara melakukannya dengan lebih baik daripada tidak sama sekali? Mungkin: setiap pemain mengirim pesan "MULAI", dan mulai segera setelah ia menerima pesan MULAI dari semua pemain lain
GameCoder
1
@StevenStadnicki Penundaan jaringan tidak membuat ini tidak mungkin. Masalah umum disebut "sinkronisasi jam" dan itu dipelajari dengan baik. (Namun, jika Anda hanya mengontrol titik akhir, maka tidak mungkin memperhitungkan keterlambatan asimetri.)
Praxeolitic
Saya mungkin salah memahami masalah Anda, tetapi bisakah Anda tidak hanya membuat pesan yang Anda kirim ke klien menunjukkan waktu mulai sedikit di masa depan? Jika waktunya tepat nowdan Anda mengirim pesan untuk memulai tepat pada now + halfSecondsaat mereka semua menerima pesan dalam setengah detik, dan selama jam sistem mereka disinkronkan dengan benar, mereka semua akan mulai pada waktu yang sama.
Markus

Jawaban:

12

Komentar Steven benar: ini secara teori tidak mungkin dilakukan.

Untungnya, dalam praktiknya Anda bisa mendekati, seperti itulah cara kerja NTP .

Misalnya, lebih baik daripada hanya mengirim pesan ke 3 klien yang mengatakan "mulai sekarang", Anda dapat bertukar beberapa pesan ping sebelumnya untuk mengukur waktu yang dibutuhkan untuk mendapatkan pesan ke klien, dan ketika Anda mengirim pesan awal, alih-alih "mulai sekarang" katakan "mulai dalam X milidetik" dan sesuaikan X untuk waktu yang berbeda yang diambil agar pesan tiba.

misalnya.:

  • Anda mengirim pesan ke Klien 1 dan mendapatkan respons kembali 20 ms kemudian. Anda menebak bahwa dibutuhkan sekitar 10 ms untuk mendapatkan pesan ke klien 1.
  • Anda melakukan hal yang sama untuk Klien 2 dan mendapatkan respons 28 ms kemudian - sehingga waktu transmisi kemungkinan ada sekitar 14 ms.
  • Jadi, Anda mengirim pesan ke Klien 1 yang mengatakan "mulai permainan dalam 50 ms" dan kirim satu ke Klien 2 yang mengatakan "mulai permainan dalam 46 ms". Klien 2 akan mendapatkan pesan tentang 4ms nanti, tetapi akan menunggu kurang dari 4ms sebelum memulai permainan.

Ini tidak dapat menjamin sinkronisasi karena waktu yang diperlukan untuk mengirim pesan di internet bervariasi, dan karena itu dapat berbeda di setiap arah. Pertama, Anda dapat mengurangi efek dengan melakukan pengukuran beberapa kali dan membaca rata-rata. Yang kedua lebih rumit dan mungkin secara teori tidak mungkin untuk dipecahkan (meskipun saya tidak dapat mengingat buktinya sekarang). Berita baiknya adalah Anda mungkin tidak membutuhkan ketepatan yang begitu banyak.

Kylotan
sumber
Saya mungkin perlu membatasi aktivitas aplikasi saya selama sinkronisasi - saat ini saya memberikan waktu CPU untuk subsistem jaringan di setiap bingkai gambar. Jika framerate adalah 30 FPS, maka saya akan menjawab ping di 1/30 = 33 ms. Saya juga bisa menambahkan 33 ms, atau perbedaan antara "TCP stack menerima waktu" dan MilisecondTicks saya saat ini () ..
GameCoder
2
Jika Anda berharap agar sistem disinkronkan dengan tepat frame-by-frame saat bermain, saya pikir itu adalah permainan yang kalah dan Anda harus menyerah sekarang. Jam dan latensi akan melayang dan informasi akan selalu membutuhkan waktu untuk bepergian. Apa pun yang Anda coba lakukan, Anda mungkin tidak memerlukan tingkat sinkronisasi ini.
Kylotan
Saya pikir kita kehilangan intinya. Bukan kesempurnaan yang mengganggu saya, ini pengalaman pengguna. Ini bisa baik atau lebih baik, dan saya ingin yang lebih baik. Itu dia.
GameCoder
2
Pengalaman pengguna yang baik tidak memerlukan sinkronisasi yang tepat. Itu sebabnya sebagian besar game tidak mencobanya.
Kylotan
1
Secara teori tidak mungkin jika masing-masing pemain mengendalikan kelelawar mereka sendiri, karena dibutuhkan waktu yang tidak nol untuk informasi tersebut untuk mencapai komputer lain, di mana kedua pihak memiliki informasi yang berbeda. Sebaliknya Anda menemukan cara untuk mengatasi perbedaan. Masalah Anda sebenarnya tidak jauh berbeda dari game online serba cepat lainnya dan ada beberapa pertanyaan lain tentang cara menangani jaringan untuk mereka di situs ini. Satu di sini: gamedev.stackexchange.com/questions/22444/…
Kylotan
3

Seperti yang disebutkan, ini tidak mungkin, jadi saya akan mencoba pendekatan lain:

Jika Anda tidak memiliki server khusus, pilih satu klien yang berpartisipasi untuk menjadi tuan rumah (ini dapat ditransfer jika perlu).

Tuan rumah sekarang akan melakukan semua logika permainan yang penting, seperti deteksi hit, kontrol AI, penanganan inventaris, dll. Serta pelacakan waktu (yaitu menentukan waktu permainan).

Klien lain hanya akan mencoba untuk tetap sinkron dengan tuan rumah, mencoba memperkirakan atau memperkirakan nilai yang diharapkan. Jika lag bertambah atau ada kehilangan paket, semuanya mungkin berombak, tetapi sepele untuk mengejar ketinggalan, pada dasarnya hanya menunggu pembaruan berikutnya.

Sebagian besar permainan (terutama FPS) menyembunyikan fakta ini dengan melakukan perhitungan lokal mereka sendiri untuk pergerakan pemain sendiri, tembakan yang ditembakkan, dll. Untuk menghindari permainan yang terasa lamban. Semuanya masih diperbaiki berdasarkan data server. Ini dapat menyebabkan beberapa kebingungan, misalnya Anda melihat diri Anda menembak musuh, tetapi pada saat yang sama Anda jatuh mati (tanpa musuh menabrak), tetapi itu masih pendekatan yang jauh lebih baik daripada sinkronisasi penuh.


Jika Anda masih bersikeras untuk menjaga semuanya tetap sinkron, Anda mungkin ingin membuat semacam penghitung langkah atau bingkai, jadi semua klien hanya memproses satu langkah logika, lalu menyinkronkan data mereka, dll. Perlu diingat bahwa ini bisa menjadi bandwidth baik intensif dan laggy, jadi saya tidak akan merekomendasikan melakukan itu kecuali Anda punya banyak data sebaliknya dan gameplay Anda berbasis giliran (misalnya gim gaya Artillery / Worms).

Mario
sumber
1

Saya merekomendasikan sinkronisasi timer sistem pada semua klien dan server dengan menggunakan protokol NTP [Stratum 2], kemudian server mengirim perintah untuk memulai permainan pada waktu yang ditentukan, katakanlah, ketika semua timer mencapai 0:05:00. Pendekatan ini seharusnya memberi Anda 3-4 ms sinkronisasi akurat, saya percaya.

ivan866
sumber