Як я можу синхронізувати стан ігор для кількох гравців ефективніше, ніж оновлення повного стану?


10

Раніше я робив невелике кодування ігрової мережі, але в першу чергу з TCP для ігор без потреб у реальному часі. Я працюю над двома грі Java з мережевим мультиплеєром. Для навчання я хочу це зробити самостійно, без наявного мережевого API.

Як я ефективно представляю стан гри, що надсилається клієнтам із сервера? Існує найбільш очевидний, але, мабуть, найменш ефективний спосіб, який би створив якийсь об’єкт контексту ігрового стану з розташуванням кожного гравця, станом анімації тощо і надсилав це кожному гравцеві кожного оновлення . Це не здається дуже складним у здійсненні, але, ймовірно, буде занадто великим, щоб досягти будь-якого, близького до взаємодії в режимі реального часу (звичайно, мій досвід з цим обмежений, тому я можу бути неправильним).

Чи існує твердий спосіб, який хтось із вас використовував раніше, щоб лише передавати зміни в стані, і чи є навіть достатньо велика невідповідність у виконанні, що варто додаткової роботи?


2
Спробуйте повний стан кожної кадрової речі, і якщо вона занадто повільна (для дещо простої 2-г грі, ймовірно, досить ефективна), тоді спробуйте оптимізувати. Якщо він працює добре, то він працює чудово, і вам не доведеться його змінювати, якщо ви не помітите, що ваша мережа є вузьким місцем пізніше.
Роберт Рухані

Відповіді:


10

Передавати повний стан гри регулярно, як правило, не представляється можливим, хоча це дуже залежить від складності вашої гри. Для простої гри з маленькою світовою моделлю вона може працювати.

Я особисто мав значно більший успіх у такій моделі:

  • Стан гри, що зберігається у чітко визначеній об'єктній моделі в структурі просторових даних (наприклад, octree)
  • Всі зміни стану гри (будь то клієнт чи сервер) описуються як події. Подія може бути зміною властивості об’єкта гри, зміною плитки карти, переміщенням ігрового об'єкта тощо.
  • Ігровий движок на сервері виробляє потік подій у процесі гри. Вони безпосередньо застосовуються до ігрового стану сервера.
  • Події також надсилаються гравцям, але лише якщо подія стосується цього гравця (наприклад, подія видно з поточної позиції?)
  • Зміни видимості гравця також можуть призвести до подій, які "розкриють" нові частини карти тощо, коли гравець рухається. Це також можна використовувати для того, щоб гравець отримав точний початковий перегляд відповідного стану гри під час першого вступу в гру.
  • Стан гри для гравця оновлюється залежно від подій, які він отримує. Як такий, він має лише часткову модель стану гри, але він повинен залишатися синхронізованим із сервером, якщо всі події правильно оброблені

Це дало хороші показники для мене навіть з досить великими ігровими світами.

Ще одна порада: дозвольте клієнту подбати про анімацію, ефекти частинок тощо без посилання на сервер. Немає сенсу їх передавати - їх просто потрібно "викликати" відповідними ігровими подіями.


6

Синхронізація зазвичай розбита на дві частини: поступову та абсолютну.

Іноді потрібно передати все, воно велике, але якщо ви упакуєте це правильно, ви можете робити це раз на кілька секунд. Добре ставити вічно на місце, виправляючи недоліки поступових оновлень.

Щоб досягти досвіду в реальному часі, ви повинні швидко передавати деякі зміни, але лише ті атрибути, які можуть змінюватися. Наприклад, якщо ракета летить по прямій лінії, вам не потрібно оновлювати позицію, кожен клієнт може обчислити її з початкової точки. Але коли він потрапить, ви можете створити повідомлення про нього, тож кожен клієнт може підірвати ракету в потрібному місці. Незначні глюки можна ігнорувати.

Звичайно, ви лише оновлюєте речі, коли вони можуть впливати на клієнта! Щось далеко за екраном не варто. Деякі значення можна оновлювати рідше. Наприклад, позиції важливі, щоб бути більш-менш точними, події (смерть, стрілянина, вибух тощо) повинні бути відправлені миттєво, тоді як не безпосередньо важливі значення можуть мати менші періоди оновлення, наприклад табло, чат.

Упаковка даних також важлива. Ви можете передати приблизно 1400 байт (залежно від конфігурації, це за замовчуванням) в одному пакеті UDP, як правило, є кілька байт заголовка. Таким чином, ви можете легко оновити 50-100 позицій одиниці в одному пакеті.


Дякую за пораду Маці. Я все ще працюю над впровадженням сервера та клієнта, але перевірте через пару днів і, ймовірно, прийму вашу відповідь.
Хаз

Удачі тобі! ;)
Маці

1

Залежно від вашої гри, ви можете розглянути модель "синхронізованого виконання", коли кожен клієнт може грати в одну і ту ж гру, просто поділившись недетермінованими входами, такими як вкладки клавіатури / джойстика та події таймера. (Порівняно з моделлю, де кожен клієнт виконує локальне моделювання та розраховує інтегрувати результати віддаленого моделювання). Ваш ігровий двигун, як правило, повинен бути повністю детермінованим, щоб це працювало, що може бути важким тягарем залежно від гри. Але якщо гра вже детермінована, це може бути простішим підходом.

Цей пост #AltDevBlogADay висвітлює деякі аспекти такого підходу в сучасній RTS (конкретно, як виявити, коли ваші клієнти починають використовувати "різні" ігри.)

Не забудьте зберігати його просто, доки не доведеться інше. :)


1
Це хороші читання від розробника Factorio, який використовує цей підхід, і натякає на складність цього підходу, але також показує, що він є життєздатним: factorio.com/blog/post/fff-76 factorio.com/blog/post/fff -147 factorio.com/blog/post/fff-188
AaronLS
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.