Linear Dead Reckoning в приложении Winsock

У меня возникли небольшие трудности с пониманием того, как я реализую Dead Reckoning в моей игре Winsock Server-Client.

Я искал в интернете достойное объяснение, которое точно объясняет:

  1. Когда сообщение должно быть отправлено с сервера клиенту

  2. Как должен действовать клиент, если он не получает обновленных сообщений, продолжает ли он использовать прогнозируемую позицию в качестве текущей позиции для расчета новой прогнозируемой позиции?

Я использую метод мертвого счета:

path vector = oldPosition - oldestPosition
delta time = oldTime - oldestTime
delta velocity = path vector / delta time
new delta time = current time / oldest time
new prediction = oldPosition + new delta time * delta velocity

Надеюсь, что это правильная формула для использования! 🙂

Следует также отметить, что тип подключения — UDP, и что игра ведется только на сервере. Сервер отправляет сообщения об обновлении клиенту.

Кто-нибудь может помочь, ответив на мои вопросы, пожалуйста?

Спасибо

4

Решение

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

Стандартный алгоритм мертвых расчетов для сетевых игр показан здесь:

Мертвое уравнение счета

Перечисленные выше переменные описаны так:

пT: Предполагаемое местоположение. Выход

пО: Самое последнее обновление позиции объекта

ВО: Последнее обновление скорости объекта

О: Самое последнее обновление ускорения объекта

T: прошедшие секунды между текущим временем и отметка времени последнего обновления — НЕ время, когда пакет был получен.

Это можно использовать для перемещения объекта до тех пор, пока обновление не будет получено с сервера. Затем у вас есть два кинематических состояния: предполагаемая позиция (самый последний результат вышеприведенного алгоритма) и только что полученная фактическая позиция. Реальное смешение этих двух состояний может быть трудным.


Одним из подходов является создание линии или, что еще лучше, кривой, такой как Сплайны Безье Сплайны Катмулла-Рома а также Кривые Эрмита (хороший список других методов Вот), между двумя государствами, все еще проецируя старую ориентацию в будущее. Итак, продолжайте использовать старое состояние, пока не получите новое — когда состояние, в которое вы переходите, становится старым.

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

Эта веб-страница, цитирующая книгу «Game Engine Gems 2», является золотым прииском для расплаты:

Правдоподобная расплата за сетевые игры

РЕДАКТИРОВАТЬ: Все вышеперечисленное только для того, как клиент должен действовать, когда он не получает обновления. Что касается «Когда сообщение должно быть отправлено с сервера на клиент», Valve говорит хороший сервер должен отправлять обновления с интервалом примерно 15 миллисекунд, примерно 66,6 в секунду.

Обратите внимание «Valve говорит«link действительно имеет несколько хороших советов по работе с сетями, используя Source Multiplayer Networking в качестве средства. Проверьте это, если у вас есть время.

РЕДАКТИРОВАТЬ 2 (обновление кода!):

Вот как я мог бы реализовать такой алгоритм в среде C ++ / DirectX:

struct kinematicState
{
D3DXVECTOR3 position;
D3DXVECTOR3 velocity;
D3DXVECTOR3 acceleration;
};

void PredictPosition(kinematicState *old, kinematicState *prediction, float elapsedSeconds)
{
prediction->position = old->position + (old->velocity * elapsedSeconds) + (0.5 * old->acceleration * (elapsedSeconds * elapsedSeconds));`
}

kinematicState *BlendKinematicStateLinear(kinematicState *olStated, kinematicState *newState, float percentageToNew)
{
//Explanation of percentateToNew:
//A value of 0.0 will return the exact same state as "oldState",
//A value of 1.0 will return the exact same state as "newState",
//A value of 0.5 will return a state with data exactly in the middle of that of "old" and "new".
//Its value should never be outside of [0, 1].

kinematicState *final = new kinematicState();

//Many other interpolation algorithms would create a smoother blend,
//But this is just a linear interpolation to keep it simple.

//Implementation of a different algorithm should be straightforward.
//I suggest starting with Catmull-Rom splines.

float percentageToOld = 1.0 - percentageToNew;

final->position = (percentageToOld * oldState->position) + (percentageToNew * new-State>position);
final->velocity = (percentageToOld * oldState->velocity) + (percentageToNew * newState->velocity);
final->acceleration = (percentageToOld * oldState->acceleration) + (percentageToNew * newState->acceleration);

return final;
}

Удачи, и если вам удастся заработать миллионы на игре, попробуйте поставить меня в титры;)

9

Другие решения

Это общий и широкий вопрос.

Если вы реализуете игровой сервер с безрассудным расчетом на стороне клиента (как я полагаю, вы делаете), вы должны продолжать оценивать значения до тех пор, пока вы не получите новый ввод с сервера. В этот момент вы должны принудительно обновить новую позицию / время / все, что вы храните. Отсутствие ответа сервера означает, что вам придется оценивать самостоятельно, основываясь на самой последней оценке.

Кстати мне кажется, что следующее

new delta time = current time / oldest time

должно быть что-то вроде

new delta time = current time - oldTime

чтобы получить время, прошедшее до последнего прогноза. В противном случае вы бы предположили, что система работала быстрее, когда прошло больше времени, и медленнее, когда прошло немного времени (по сравнению с самым старым временем, использованным как единица измерения). Уравнение линейного движения (не ускоренное): new_s = s_0 + vel * t

1

По вопросам рекламы [email protected]