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


14

Я працюю над дворівневою ігровою системою багатокористувацької гри 2 сервер-клієнт (яку ви можете спробувати тут ). Він використовує WebRTC DataChannels. (З'єднання однорангові, але хост-рівномірний все ще діє як сервер.)

Найбільша проблема (крім підключення) - передбачення локального вводу. Ми робимо звичайне: при натисканні клавіш гравці миттєво рухаються, повідомляють господареві, які клавіші натискаються, отримують дані від хоста і порівнюють їх з історичною позицією. Позиція виправляється з часом, якщо є різниця. Це добре працює з низькими втратами пакетів або ПДВ , навіть якщо ping великий.

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

Якщо гравець рухається, ми відкручуємо суму застосованої корекції, оскільки це менш помітно. Це, здається, приховує прогалини під час початку руху та під час руху. Однак будь-яке виправлення помітніше, якщо вони різко зупиняються. Тоді, якщо ПДВ або втрата означає, що хост вважає, що вони зупинилися пізніше, хост перестає зніматися, надсилає назад дані, кажучи, що вони трохи далі вперед, і виправлення змушує плеєра трохи дрейфувати. На нестійких з'єднаннях гравці часто помітно дрейфують після зупинки.

Я цього не помічав в інших іграх. Як це можна пом'якшити?


3
Гра P2P, у якій є сервер? Тут щось не так.
API-Beast

На жаль, під "сервером" я маю на увазі "узгоджений партнер".
AshleysBrain

2
Ну, це не схоже на модель однорангових, тільки тому, що один з гравців ставить себе за те, що сервер не робить його одноранговим. Ви використовуєте техніку, безумовно, техніку клієнт-сервер. У P2P ви або повністю довіряєте всім клієнтам (наприклад, кожен одноліток запитує один одного однолітка, де знаходиться його гравець), або ви не довіряєте жодному (наприклад, ви затримуєте введення, поки всі однолітки не отримали його).
API-Beast

Ага ... це хороший момент насправді ... Я переплутався: з'єднання однорангові (це те, що робить WebRTC), але сам двигун - сервер-клієнт (один із партнерів - це лише сервер ). Гарна думка.
AshleysBrain

2
Те , що це змушує мене думати про те , наш власний Andrew Russell «s Стік Ninjas Dev журнали на YouTube , в зокрема , це один на виправлення помилок прогнозування . Дрифтинг, який ви описуєте, звучить дуже схоже на те, що відбувається у цьому відео, і Ендрю розповідає подробиці. Це пов'язані чи, можливо, навіть те саме питання?
Анко

Відповіді:


8

Мережевий рівень повинен мати погоджений годинник. Вони можуть домовитись про тактове значення на початку гри (і періодично повторно синхронізувати його у випадку дрейфу), тому господар знає, скільки часу потрібно було дістати конкретному пакету і коли клієнт здійснив дію, і навпаки.

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

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

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

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

Серверу потрібно перевірити годинник введення та переконатися, що вони не надто сильно залежать від очікувань, щоб запобігти обману. Час введення не повинен бути значно більшим, ніж час, який ви обчислюєте в півтора рази. Затиснути будь-які, що знаходяться в розумному діапазоні ( [Now-2*RTT,Now]наприклад).

Клієнти побачать багато тремтіння аватарів інших гравців, якщо затримка буде великою, оскільки вони отримуватимуть оновлення від сервера на основі несвідомого введення, але не мають змоги знати, що це несвіже, і тоді сервер може почати надсилати досить різні місця на основі оновлене введення, яке воно отримало (і випадання деякої частини його історії та відтворення його новим входом). Цей останній випуск з іншими гравцями, які бачать ваш тремтіння аватара, насправді не виправлений. Затримка відстійників та геймерів, застряглих у зв’язках із високою затримкою, побачать багато тремтіння інших гравців, навіть якщо власний гравець плавно рухається. Єдина корекція - грати на кращих з'єднаннях або з одноранговими / серверами з меншою затримкою.


1

Я використовував надійні повідомлення UDP для вказівки змін стану кнопки та ненадійних повідомлень UDP для виправлення позиції. В основному мені дуже допомогли наступні статті: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking

Він говорить про передбачення руху за допомогою зберігання станів гравців у постійних часових інтервалах відповідно до повідомлень про корекцію позицій приблизно на 20 або 30 економії стану. Таким чином, схоже, що ваші віддалені гравці житимуть у не так далеко "минулому" фактично, постійно застосовуючи техніку прогнозування :) На основі чистої затримки повідомлення ви можете отримати своє об'єктне положення приблизно в той час, коли повідомлення було щойно відправлене від хоста.

Поточне положення "на екрані" може бути потім плавно переведене в передбачуване положення за допомогою математики Lerp (лінійна інтерполяція). Ідея полягає в інтерполяції значень у часові проміжки між пакетами виправлення. Таким чином, схоже, що відображається об'єкт завжди рухається до певної передбачуваної позиції. Для значення інтерполяції я беру 1, поділене на "затримку середнього повідомлення", поділене на "час кадрування середнього кадру", тому рух виглядає плавним.

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

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

Я описав всю схему, яку я використав у своєму проекті, тому сподіваюся, ви знайдете відповідь на своє запитання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.