Синхронизация соперника по сети. Лаги/рывки/дергания

Сеть в Unity3D

Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Nolex 20 май 2017, 16:24

Делаю мультиплеер для гоночной игры на UNET (Unity Networking).

СУТЬ ПРОБЛЕМЫ:

Перебрав множество вариантов реализаций Интерполяции/Экстраполяции остановился на одной наиболее подходящей, но осталась одна проблема:

Соперник по задумке отсылает данные каждые 0.05 сек, но в реальности они приходят с разной задержкой из-за чего случаются лаги/рывки/дергания соперника:
0.050 - 5% случаев.
0.066 - 90% случаев.
0.082 - 5% случаев.

Если пакеты приходят стабильно через одинаковый интервал (напр. 0.066 сек), то все идеально.

ВИДЕО (на 5й секунде начинаются проблемы):




КОД:

Синтаксис:
Используется csharp
const float interval_send = 0.05f; // Шлем данные каждые 0.05 sec (50 ms)

// Получаем данные от соперника
void OnGetPosition(Vector3 _new_position, Vector3 _new_velocity)
    {
            last_position = transform.position;

            new_position = _new_position;
            new_velocity = _new_velocity;

            float real_update_interval = (Time.time - lastUpdateTime); // для Дебага.
            Debug.Log("Real Update Interval: " + real_update_interval); // 0.050.....0.066.....0.082 sec.
            lastUpdateTime = Time.time;
    }

void Update()
    {
            float pctDone = (Time.time - lastUpdateTime) / interval_send;

            if (pctDone <= 1.01f)
            {
                trans.position = Vector3.Lerp(last_position, new_position, pctDone); // Интерполяция
            }
            else
            {
                trans.position = trans.position + (new_velocity *Time.deltaTime); // Экстраполяция
            }
    }

 



Подозреваю, что надо в коде учитывать как-то эти временные задержки/скачки, но все что я пробовал пока не помогло.

Какие варианты?
Спасибо!
Разработка игр в студии Brinemedia .
Аватара пользователя
Nolex
UNIверсал
 
Сообщения: 483
Зарегистрирован: 17 окт 2010, 12:26
Откуда: Украина
Skype: exlumen
  • Сайт
  • ICQ

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Aleksey 20 май 2017, 19:15

Синтаксис:
Используется csharp
void OnGetPosition(Vector3 _new_position)
    {
            new_position = _new_position;
    }

void Update()
    {
           transform.position = Vector3.Lerp(transform.position, new_position, ime.deltaTime*5);
    }


Такой вариант обгоняет позиции? поедее не должен. Если не обгоняет НО слишком долго догоняет конец отрезка лерпа то можно к примеру добавить велосити к передаче
И я не очень понял как передается велосити.Я это представляю так . Если добавить велосити к скрипту выше. То будет следующие -
Синтаксис:
Используется csharp
void OnGetPosition(Vector3 _new_position, Vector3 _new_velocity)
    {
            new_position = _new_position;
            GetComponent<Rigidbody2D>().velocity = _new_velocity;
    }

void Update()
    {
           transform.position = Vector3.Lerp(transform.position, new_position, ime.deltaTime*5);
    }


Добавление передачи велосити к динамически изменяющимся третьему параметру Лерпу почти всегда сулит такие лаги как у тебя. Третий параметр Лерпа делают динамически изменяемым для того чтобы максимально быстро пройти путь от начало до конца отрезка Лерпа и конечно если ты в это добавишь еще и велосити, то ты будешь обгонять конец отрезка лерпа.Ну если не обгонять, то как минимум догонять его и останавливаться ожидаю новую позицию от сети.
Простой пример такой же технологии ток чуток попроще. Еще в ней обнуляется fraction когда получаем позицию от игрока. И в ней тоже добавление велосити приводит к обгонам конца отрезка. Первый пример который я тебе показал не добавляет баги потому что он рисует очень много точек в отрезке лерпа из-за того что у него динамическое начало отрезка
Синтаксис:
Используется csharp
    void Update()
    {
        if (photonView.isMine)    return;    
       
        fraction = fraction + Time.deltaTime * 9;
        transform.localPosition = Vector3.Lerp(onUpdatePos, latestCorrectPos, fraction);
        transform.localRotation = Quaternion.Lerp(onUpdateRot, latestCorrectRot, fraction);
    }
Продукты на тему онлайна в Ассет Сторе
_https://www.assetstore.unity3d.com/en/# ... sher:21589
Аватара пользователя
Aleksey
UNIт
 
Сообщения: 56
Зарегистрирован: 17 фев 2015, 16:09

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Nolex 21 май 2017, 16:43

Синтаксис:
Используется csharp
transform.position = Vector3.Lerp(transform.position, new_position, ime.deltaTime*5);
 

Знаю про такой подход Интерполяции и он довольно плохой. С ним будет плавно и очень неточно ИЛИ будет лагать, но с улучшенной точностью (в зависимости от коефициента Time.deltaTime * SmoothFactor).
Этот вариант больше подходит для Интерполяции второстепенных объектов, например камеры игрока.

К слову, я проводил тесты и теория подтвердилась на практике. Не советую такой вариант.
Вот хорошая ссылка по этой теме: https://gamedev.stackexchange.com/quest ... unity-game

И я не очень понял как передается велосити.

Ммм. Вон же в Update() используется, смотри последнюю строчку. Rigidbody тут не нужен. )
Если по каким-то причинам, происходит задержка пакета, то Экстраполируем. Просто прибавляем нашу скорость каждый кадр (new_velocity * Time.deltaTime):

Синтаксис:
Используется csharp
transform.position = transform.position + (new_velocity * Time.deltaTime); // Экстраполяция
 


Спасибо за активность в теме :)

Вопрос открыт. Еще советы?
Разработка игр в студии Brinemedia .
Аватара пользователя
Nolex
UNIверсал
 
Сообщения: 483
Зарегистрирован: 17 окт 2010, 12:26
Откуда: Украина
Skype: exlumen
  • Сайт
  • ICQ

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Aleksey 21 май 2017, 17:39

Ладно Ладно ты прав.) Но у тебя все равно экстраполяция обгоняет интерполяцию(конец отрезка лерпа). Ты понимаешь это ?) Тебе нужно либо уменьшать велосити ,либо рисовать больше точек в лерпе а в этом случае тогда надо брать приблизительно мой вариант расчета лерпа где в первом параметре лерпа динамическое начало отрезка или уменьшать опять же коэффициент лерпа чтобы рисовал больше точек

Окей тогда посмотрим с другой стороны на твой пример.Я не понимаю как решается его следующий минус. Из-за того что ты так там веселишься с коэффициентом лерпа(с учетом того что там считается как я понял время между получением каждой позиции) то у тебя очень часто рисуется разное количество точек в отрезке лерпа. В итоге объект передвигается с разной скоростью по таким отрезкам лерпа от last_position до new_position из-за разнообразно прыгающего коэффициента. Или это просто не видно глазами. Пример лучше сглаживает потери пакетов позиций да, Но когда все более менее нормально мне кажется там не очень все круто. Нужно больше тестов мне)))))

По ссылке неплохие рассуждения! Спасибо. Прям свои мысли как будто открыл только в другой форме немного
Продукты на тему онлайна в Ассет Сторе
_https://www.assetstore.unity3d.com/en/# ... sher:21589
Аватара пользователя
Aleksey
UNIт
 
Сообщения: 56
Зарегистрирован: 17 фев 2015, 16:09

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Nolex 21 май 2017, 18:36

Aleksey писал(а):Ладно Ладно ты прав.) Но у тебя все равно экстраполяция обгоняет интерполяцию(конец отрезка лерпа). Ты понимаешь это ?) Тебе нужно либо уменьшать велосити ,либо рисовать больше точек в лерпе а в этом случае тогда надо брать приблизительно мой вариант расчета лерпа где в первом параметре лерпа динамическое начало отрезка или уменьшать опять же коэффициент лерпа чтобы рисовал больше точек
По ссылке неплохие рассуждения! Спасибо. Прям свои мысли как будто открыл только в другой форме немного

Что значит обгоняет? Экстраполяция - это по сути предсказание того, где будет машинка в следующем кадре.
Может обгонять, а может и отставать, НО конкретно эта реализация работает очень хорошо, т-к за 50-100 ms скорость сильно не меняется и ее можно смело применять.

Совет уменьшить velocity - это глупость. Это будет принудительное торможение объекта в случае задержки пакетов.
Совет про больше точек в лерпе - тоже самое. К чему это? Точек всегда одинаково будет, они ж каждый кадр рисуются, тут вопрос скорее в позициях/времени и вообще в концепции синхронизации.

Aleksey писал(а):Окей тогда посмотрим с другой стороны на твой пример.Я не понимаю как решается его следующий минус. Из-за того что ты так там веселишься с коэффициентом лерпа(с учетом того что там считается как я понял время между получением каждой позиции) то у тебя очень часто рисуется разное количество точек в отрезке лерпа. В итоге объект передвигается с разной скоростью по таким отрезкам лерпа от last_position до new_position из-за разнообразно прыгающего коэффициента. Или это просто не видно глазами. Пример лучше сглаживает потери пакетов позиций да, Но когда все более менее нормально мне кажется там не очень все круто. Нужно больше тестов мне)))))

Вот как раз наоборот. Когда стабильно приходят пакеты, то "все круто", как ты говоришь. ;)
Посмотри на видео первые 5 секунд - там все ок. А вот дальше, когда пакеты немного задерживаются, то есть некоторые проблемы.

Подозреваю, что ты не совсем понимаешь как работает эта концепция синхронизации.
Вот тут, например, можно почитать про эту модель Интерполяции/Экстраполяции на конкретном примере: https://www.raywenderlich.com/88078/cre ... ity-part-3
Разработка игр в студии Brinemedia .
Аватара пользователя
Nolex
UNIверсал
 
Сообщения: 483
Зарегистрирован: 17 окт 2010, 12:26
Откуда: Украина
Skype: exlumen
  • Сайт
  • ICQ

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Aleksey 21 май 2017, 18:45

как это одинаковое количество точек рисуется? у тебя же меняется pctDone.Я про это. Одинаковое количество точек ведь в этом примере только тогда когда третий коэффициент неизменяемый
trans.position = Vector3.Lerp(last_position, new_position, pctDone); // Интерполяция

Подозреваю, что ты не совсем понимаешь как работает эта концепция синхронизации.
Ну да. не спорю. Я такой вариант не тестировал и не разбирал))

спасибо за ссылку))
Вот тут, например, можно почитать про эту модель Интерполяции/Экстраполяции на конкретном примере: https://www.raywenderlich.com/88078/cre ... ity-part-3



Посмотри на видео первые 5 секунд - там все ок. А вот дальше, когда пакеты немного задерживаются, то есть некоторые проблемы.

А почему тогда лаги ровно в точках где резкие изменения скорости автомобиля? Совпадение?
в смысле какой ток на 5 секунде. Давай все карты вскрываем из под шубы. На первой секунде что? там трешак полный, он прыгает вперед(это велосити обгоняет лерп). Это не от задержки пакета уж точно.

Да какой норм движение он на каждой кочке дергается вперед а потом возвращается

https://www.youtube.com/watch?v=GmCXraKxMs4
вот например лаг задержки пакета. 41-42 секунда моего проекта. Вот это да. задержки пакета позиций. а у тебя обгоны на видео. причем тут задержки пакета

Видео с показателями пинга не помешало бы. Я думаю это не в этих точках задержки лаг .
Продукты на тему онлайна в Ассет Сторе
_https://www.assetstore.unity3d.com/en/# ... sher:21589
Аватара пользователя
Aleksey
UNIт
 
Сообщения: 56
Зарегистрирован: 17 фев 2015, 16:09

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Nolex 21 май 2017, 21:15

Aleksey писал(а):как это одинаковое количество точек рисуется? у тебя же меняется pctDone.Я про это. Одинаковое количество точек ведь в этом примере только тогда когда третий коэффициент неизменяемый

Речь не про это. Ты писал про "больше точек в лерпе", а я говорю что это глупость, т-к их в моем случае, в целом, получается одинаковое кол-во. "Недостающие" точки добавляет экстраполяция. Разница в концепциях просто. У тебя более простая реализация.

Aleksey писал(а):А почему тогда лаги ровно в точках где резкие изменения скорости автомобиля? Совпадение?

Совпадение. Резкие изменения скорости тут не при чем.
Я продебажил все много и раз не просто так делаю акцент на интерполяции и задержке пакетов.

В итоге, вот ты предлагаешь опять тоже самое, что написал в предыдущих сообщениях.
Я ж выше объяснил, что этот подход не работает и ссылку скинул на stackexchange, где расписано почему так.
Aleksey, спасибо за попытки помочь, но давай уже по существу либо подождем пока кто-то более опытный ответит. :)

Вопрос открыт. У кого есть реальные идеи - буду премного благодарен.
Разработка игр в студии Brinemedia .
Аватара пользователя
Nolex
UNIверсал
 
Сообщения: 483
Зарегистрирован: 17 окт 2010, 12:26
Откуда: Украина
Skype: exlumen
  • Сайт
  • ICQ

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Ert Donuell 23 май 2017, 05:19

Если игроки не могут выбирать оппонентов, то самый читерный вариант - это загружать уже обкатанные сессии других игроков. Зачем передавать позицию в риалтайме, если можно передавать все её состояния заранее? :D
Добавить dmitrii.baranov.yumasoft в Skype
Аватара пользователя
Ert Donuell
Старожил
 
Сообщения: 781
Зарегистрирован: 05 июл 2010, 09:50
Откуда: Санкт-Петербург
  • ICQ

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Nolex 23 май 2017, 19:46

Ert Donuell писал(а):Если игроки не могут выбирать оппонентов, то самый читерный вариант - это загружать уже обкатанные сессии других игроков. Зачем передавать позицию в риалтайме, если можно передавать все её состояния заранее? :D

Ха-ха)) Хитрость - это хорошо, но в данном случае это риал-тайм гонка, где можно выбрать например, друга.

Вопрос по прежнему открыт.

В общем, после множества дебагов я четко вижу, что проблема в том, что пакеты приходят не равномерно, в частности, из-за ФПС. Эти +-0.016 sec, которые требуются для обновления кадра при 60 FPS.
В итоге точка по который интерполируется скачет :)

Либо костыль прикручивать надо, либо другой подход использовать.
Разработка игр в студии Brinemedia .
Аватара пользователя
Nolex
UNIверсал
 
Сообщения: 483
Зарегистрирован: 17 окт 2010, 12:26
Откуда: Украина
Skype: exlumen
  • Сайт
  • ICQ

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Nolex 23 май 2017, 22:24

Подробные логи с примером лага

Цвета:
Зеленым - Оптимальный интервал между получкой последнего пакета и текущего
Оранжевым - Подозрительный интервал
Красным - Большие перепады в передвижении по сравнению с предыдущим кадром.


OnGetPosition. Data #335. LocalUpdateInterval: 0.06622314, OpponentUpdateInterval: 0.06616211
LastPosition: 191.8967, NewPosition: 192.3506, NewVelocity: (0.0, 2.9, 8.2)
Interpolate (by Lerp). PosZ: 192.1984 (from 191.8967 to 192.3506, pctDone: 0.6646729 of 1)
End Update(). OBJECT MOVED: +0.3016968, Time.deltaTime: 0.03323241
Extrapolate (Velocity). PosZ: 192.4712 (velocity (0.0, 2.9, 8.2) * 0.03330375 deltaTime)
End Update(). OBJECT MOVED: +0.2727966, Time.deltaTime: 0.03330375

OnGetPosition. Data #336. LocalUpdateInterval: 0.06653786, OpponentUpdateInterval: 0.06640625
LastPosition: 192.4712, NewPosition: 192.9164, NewVelocity: (0.0, 2.2, 8.2)
Interpolate (by Lerp). PosZ: 192.7664 (from 192.4712 to 192.9164, pctDone: 0.6632233 of 1)
End Update(). OBJECT MOVED: +0.2952576, Time.deltaTime: 0.03316254
Extrapolate (Velocity). PosZ: 193.0395 (velocity (0.0, 2.2, 8.2) * 0.03323329 deltaTime)
End Update(). OBJECT MOVED: +0.2730103, Time.deltaTime: 0.03323329
Extrapolate (Velocity). PosZ: 193.3125 (velocity (0.0, 2.2, 8.2) * 0.03323388 deltaTime)
End Update(). OBJECT MOVED: +0.2730103, Time.deltaTime: 0.03323388

OnGetPosition. Data #337. LocalUpdateInterval: 0.09962845, OpponentUpdateInterval: 0.06640625
LastPosition: 193.3125, NewPosition: 193.4863, NewVelocity: (0.0, 1.8, 8.3)
Interpolate (by Lerp). PosZ: 193.428 (from 193.3125 to 193.4863, pctDone: 0.6646729 of 1)
End Update(). OBJECT MOVED: +0.1155243 <-- Maybe problem with value!, Time.deltaTime: 0.033233

OnGetPosition. Data #338. LocalUpdateInterval: 0.03323364, OpponentUpdateInterval: 0.06665039
LastPosition: 193.428, NewPosition: 193.9866, NewVelocity: (0.0, 0.6, 6.2)
Interpolate (by Lerp). PosZ: 193.7993 (from 193.428 to 193.9866, pctDone: 0.6646729 of 1)
End Update(). OBJECT MOVED: +0.3712921 <-- Maybe problem with value!, Time.deltaTime: 0.03323329
Extrapolate (Velocity). PosZ: 194.0043 (velocity (0.0, 0.6, 6.2) * 0.03323388 deltaTime)
End Update(). OBJECT MOVED: +0.2050629 <-- Maybe problem with value!, Time.deltaTime: 0.03323388

OnGetPosition. Data #339. LocalUpdateInterval: 0.06646729, OpponentUpdateInterval: 0.06640625
LastPosition: 194.0043, NewPosition: 194.4259, NewVelocity: (0.0, 0.1, 6.4)
Interpolate (by Lerp). PosZ: 194.2846 (from 194.0043 to 194.4259, pctDone: 0.6646347 of 1)
End Update(). OBJECT MOVED: +0.2802124 <-- Maybe problem with value!, Time.deltaTime: 0.03323241
Extrapolate (Velocity). PosZ: 194.4982 (velocity (0.0, 0.1, 6.4) * 0.03331047 deltaTime)
End Update(). OBJECT MOVED: +0.2136078 <-- Maybe problem with value!, Time.deltaTime: 0.03331047
Extrapolate (Velocity). PosZ: 194.7108 (velocity (0.0, 0.1, 6.4) * 0.0331564 deltaTime)
End Update(). OBJECT MOVED: +0.212616, Time.deltaTime: 0.0331564



В общем, там четко видно что в пакет #337 пришел на 1 кадр позже (1/30 = 0.0333), со интервалом в 0.099.., вместо обыного 0.066. Из-за этого пошли сбои.

А интервал жестко задан (который используется в Lerp):
Синтаксис:
Используется csharp
const float interval_send = 0.05f;

А тут получается для пакета #337 интервал получился в 2 раза больше и Lerp работает уже не так, как надо.

Да, я пробовал для Lerp использовать не 0.05, а последний LocalUpdateInterval из пакета, НО конкретно этот случай полечит, но появляются схожие проблемы в других местах.
Т.е. по факту проблема остается.

Пробовал игратся с показателями FPS/LocalUpdateInterval/OpponentUpdateInterval.
Много экспериментировал, прикручивал коеффициенты - пока безуспешно. :(
Разработка игр в студии Brinemedia .
Аватара пользователя
Nolex
UNIверсал
 
Сообщения: 483
Зарегистрирован: 17 окт 2010, 12:26
Откуда: Украина
Skype: exlumen
  • Сайт
  • ICQ

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Ert Donuell 24 май 2017, 23:02

А в FixedUpdate передавать данные можно?
Добавить dmitrii.baranov.yumasoft в Skype
Аватара пользователя
Ert Donuell
Старожил
 
Сообщения: 781
Зарегистрирован: 05 июл 2010, 09:50
Откуда: Санкт-Петербург
  • ICQ

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Tolking 25 май 2017, 03:01

Мысль такая: когда ты получил данные от другого клиента - это уже прошлое всегда, при любом раскладе и интервале...
Ковчег построил любитель, профессионалы построили Титаник.
Аватара пользователя
Tolking
Адепт
 
Сообщения: 2714
Зарегистрирован: 08 июн 2009, 18:22
Откуда: Тула

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Nolex 25 май 2017, 19:14

Ert Donuell писал(а):А в FixedUpdate передавать данные можно?

Можно, но что это поменяет? Всеравно пакеты могут приходить в разное время и скачки точки в Lerp это не вылечит.

Tolking писал(а):Мысль такая: когда ты получил данные от другого клиента - это уже прошлое всегда, при любом раскладе и интервале...

Очень верно подмечено. Но это легко решается добавлением к позиции + (new_velocity * interval_send).

Т.е. это не проблема на самом деле. Основная проблема, которая пока не решана, описана выше.
Разработка игр в студии Brinemedia .
Аватара пользователя
Nolex
UNIверсал
 
Сообщения: 483
Зарегистрирован: 17 окт 2010, 12:26
Откуда: Украина
Skype: exlumen
  • Сайт
  • ICQ

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Tolking 25 май 2017, 23:22

Почему новую скорость добавлять, а не старую? Или не среднюю? И почему умножать на интервал пересылки если прошло больше по-любому (ведь верно подмечено?)
От откуда вообще берется интерполяция позиции? Всегда должна быть только экстрополяция. Мы должны рассчитать где сейчас находится противник и это положение экстрополировать в зависиммости от поступивших данных... Не должен подход прыгать туда-сюда по условию... Позиция противника должна всегда экстраполироваться, а вот его отображение противника должно интерполироваться к его положению...
Ковчег построил любитель, профессионалы построили Титаник.
Аватара пользователя
Tolking
Адепт
 
Сообщения: 2714
Зарегистрирован: 08 июн 2009, 18:22
Откуда: Тула

Re: Синхронизация соперника по сети. Лаги/рывки/дергания

Сообщение Nolex 28 май 2017, 01:26

Tolking писал(а):Почему новую скорость добавлять, а не старую? Или не среднюю? И почему умножать на интервал пересылки если прошло больше по-любому (ведь верно подмечено?)
От откуда вообще берется интерполяция позиции? Всегда должна быть только экстрополяция. Мы должны рассчитать где сейчас находится противник и это положение экстрополировать в зависиммости от поступивших данных... Не должен подход прыгать туда-сюда по условию... Позиция противника должна всегда экстраполироваться, а вот его отображение противника должно интерполироваться к его положению...

А что даст, если добавлять старую скорость? Или среднюю? По сути, ж ничего не поменяется)

На счет интервала пересылки, да. Есть такое, я уже пробовал использовать реальное время пересылки, а не константу interval_send. Это не решило проблему.

Я пробовал экстраполировать таким способом:
Синтаксис:
Используется csharp
 void Update() { transform.position += (new_velocity * Time.deltaTime); }


Но что-то не то.
Можешь реально предложить какой-то рабочий вариант? Могу код протестировать.
Разработка игр в студии Brinemedia .
Аватара пользователя
Nolex
UNIверсал
 
Сообщения: 483
Зарегистрирован: 17 окт 2010, 12:26
Откуда: Украина
Skype: exlumen
  • Сайт
  • ICQ

След.

Вернуться в Сеть

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


cron