2016-10-11 2 views
12

Я написал многопользовательский понг, используя UDP. Я использую интерполяцию и экстраполяцию, чтобы создать гладкий эффект для клиента.Будет ли «Резиновая лента» разрешать многопользовательскую интерполяцию заикания?

Это работает. Тем не менее, в мяче есть немного постоянных заиканий. Он перебрасывает крошечный бит вперед каждый раз, когда принимается новый пакет. Он выглядит немного лагги, но он воспроизводим.

Должен быть способ сделать игру более гладкой. Я читал о Rubber Banding. Какой был бы лучший способ перейти отсюда?

Я надеюсь, что тот, кто сможет ответить на мой вопрос, найдет его.

Update

По просьбе Ивана, здесь график времени пинг. Тем не менее, я действительно считаю, что проблема существует внутри кода сглаживания клиента.

enter image description here

+0

Кстати, вы измеряли ping/fps? – Ivan

+0

@ Ivan Я измеряю Ping, да. Тем не менее, я не использую его в данный момент. – Z0q

+0

Я спрашиваю об этих показателях, чтобы мы могли количественно определить, что такое «немного лагги» и в каких обстоятельствах. Например. если ваш пинг составляет 900 мс, в основном любой опыт в порядке – Ivan

ответ

6

Заполнение с контекстом из вашего previous question, я понимаю, что вы отправляете лопатка & мяч позиции от каждого клиента к другому. Однако, пока клиенты соглашаются, где весла находятся в каждый момент времени, движение шара полностью определяется (исключая ошибки округления), и вы должны экспериментировать с нулевым шариком. Каждый клиент должен иметь собственное внутреннее состояние с положением и скоростью лопастей и мяча. Псевдокод будет похож на следующее:

// input thread 
if input changed, 
    alter paddle speed and/or direction 
    send timestamped message to inform my opponent of paddle change 

// incoming network thread 
if paddle packet received 
    alter opponent's paddle speed and/or direction at time it was sent 
    fix any errors in previously extrapolated paddle position <--- Easy 
if ball-packet received 
    fix any errors in ball position and speed <--- Tricky 

// update entities thread 
for each entity (my paddle, opponent paddle, the ball) 
    compute updated entity position, adjusted by time-since-last-update 
    if ball reached my end, send ball-packet to other side 
    draw updated entity 

Это предполагает, что происходит обмен двух типов пакетов:

  • весло пакеты датируемые позиции + скорости весел, и посылаются всякий раз, когда клиент изменяет скорость собственного весла.
  • Шариковые пакеты - это временные позиции + скорости мяча и отправляются всякий раз, когда мяч достигает стороны клиента (локальной), независимо от того, отскакивает ли она от весла или нет.

Псевдокод выполняет экстраполяцию («предположим, что все продолжает двигаться как обычно») для всех неизвестных в потоке объектов обновления. Единственный момент, когда возникают проблемы, отмечен стрелками <---.

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

Исправить положение мяча легко, если оба клиента более или менее согласны (и затем вы можете снова сделать интерполяционный трюк, чтобы сгладить его дальше). Тем не менее, один клиент может видеть близость, а другой - ближний удар. В этом случае, поскольку вы используете одноранговую модель, мы позволяем локальному клиенту совершать вызов и объяснять, что произошло с противником (в другом дизайне у вас будет центральный сервер, принимающий такие решения; это хорошо, чтобы избежать обмана). Вы не можете избегать уродливого прыжка там, если оба клиента не согласны - но, надеюсь, это должно быть относительно редко и коротко, если оно не совпадает с пингом пинга.

+0

Привет, спасибо за ваш ответ. Это не мой предыдущий вопрос. Как избежать этих прыжков, если оба клиента не согласны? Это мой вопрос – Z0q

+0

И мой ответ заключается в том, что вы слишком часто обмениваете неправильный тип информации, что приводит к частым и избегаемым разногласиям. Вы должны обмениваться информацией только с клиентом, который знает что-то с тем, кто еще не знает об этом, а затем доверяет входящую информацию. Клиент B не может знать, какие движки paddle Клиент A недавно сделал из-за сетевых задержек. Таким образом, клиент B не должен указывать Клиенту все, что касается движений Клиента A. – tucuxi

2

Одна из идей, которая позволяет избавиться от этого эффекта: Использование сглаживания при применении исправлений ошибок прогнозирования на клиенте.

Как это работает

В какой-то момент в коде вы определить, что положение шара и клиента различны.

Discrepancy

Вместо применения, что в качестве поправки к коду клиента сразу (это одна из причин вы можете увидеть эти прыжки), вы выполняете, что в течение некоторого времени, например cl_smoothtime 500мс.

Сначала ваша программа должна хранить время, когда произошло событие обнаружения ошибки m_flPredictionErrorTime.

public void onErrorDetected() { 
    this.m_flPredictionErrorTime = System.currentTimeMillis(); 
} 

Где-то рядом с отображаемым кодом вы подсчитываете, сколько ошибок вы собираетесь отображать. Вот для этого несколько псевдокодов.

public void draw() { 
    Point preditctionError = this.clientPredictedBallCoordinates - this.serverCoordinates; 
    Point deltaToDisplay = calculateErrorVector(preditctionError); 
    Point positionToDisplay = clientPredictedBallCoordinates + deltaToDisplay; 
    // actually draw the ball here 
} 

public Point calculateErrorVector(Point coordinatesDelta) { 
    double errorAmount = (System.currentTimeMillis() - this.m_flPredictionErrorTime)/this.cl_smoothtime. 
    if (errorAmount > 1.0) { 
     // whole difference applied in full, so returning zero delta 
     return new Point(0,0); 
    } 
    if (errorAmount < 0) { 
     // no errors detected yet so return zero delta 
     return new Point(0,0); 
    } 
    Point delta = new Point(coordinates.x*errorAmount, coordinates.y*errorAmount); 
    return delta; 
} 

Я выбрал эту идею от Source Multiplayer Networking wiki. Пример фактического кода в Cpp доступен в их SDK около GetPredictionErrorSmoothingVector function.