Алгоритм движения в клиент-серверных многопользовательских (MMO) играх?

Я писал двухмерную многопользовательскую флеш-игру и сервер сокетов. Мой первоначальный план алгоритма движения между клиентом и сервером был следующим:

  • The client informs the server about the player's movement mode (moving forward or not moving) and the player's turning mode (not turning, turning left or turning right) whenever these change.
    • The server loops all players every few milliseconds and calculates the angle turned and distance moved, based on the difference in time. The same calculation is done by the client.

Мой текущий расчет для клиента (та же математика используется на сервере) ==>

Поворот

var newTimeStamp:uint = UtilLib.getTimeStamp(); //set current timeStamp
                var rot:uint = Math.round((newTimeStamp - turningTimeStamp) / 1000 * 90); //speed = x degrees turning every 1 second
                turningTimeStamp = newTimeStamp; //update timeStamp
                if (turningMode == 1) //left
                {
                    movementAngle = fixAngle(movementAngle - rot);
                }
                else if (turningMode == 2) //right
                {
                    movementAngle = fixAngle(movementAngle + rot);
                }

private function fixAngle(angle:int):uint //fixes an angle in degrees (365 -> 5, -5 -> 355, etc.)
        {
            if (angle > 360)
            {
                angle -= (Math.round(angle / 360) * 360);
            }
            else if (angle < 0)
            {
                angle += (Math.round(Math.abs(angle) / 360) + 1) * 360;
            }
            return angle;
        }

Движение

var newTimeStamp:uint = UtilLib.getTimeStamp(); //set current timeStamp
                var distance:uint = Math.round((newTimeStamp - movementTimeStamp) / 1000 * 300); //speed = x pixels forward every 1 second
                movementTimeStamp = newTimeStamp; //update old timeStamp
                var diagonalChange:Array = getDiagonalChange(movementAngle, distance); //with the current angle, howmuch is dX and dY?
                x += diagonalChange[0];
                y += diagonalChange[1];

private function getDiagonalChange(angle:uint, distance:uint):Array
        {
            var rAngle:Number = angle * Math.PI/180;
            return [Math.round(Math.sin(rAngle) * distance), Math.round((Math.cos(rAngle) * distance) * -1)];
        }

Кажется, это отлично работает. Чтобы учесть задержку, сервер время от времени корректирует информацию о клиенте, отправляя эти данные.

В этой системе очень мало пропускной способности используется для управления движением. Однако разница между координатами и углами моего сервера и клиента слишком велика. Должен ли я расширить свой «алгоритм», чтобы также учитывать задержку, которую имеет пользователь? Или есть лучшие способы управления движением в клиент-серверных многопользовательских играх с высокой производительностью?


person Tom    schedule 30.06.2009    source источник


Ответы (3)


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

Таким образом, если ваша последняя зарегистрированная позиция была X, следующая должна быть в радиусе от X, где радиус основан на разнице временных меток, отправленных клиентом с данными x, y.

В основном это просто необходимо для выявления читерства.

Остановка, бой и т. д. потребуют отправки позиции вместе с атакой, а действия, инициированные позициями, будут инициированы только после того, как клиент отправит обновление для этой позиции, но будут основаны на сервере.

Не уверен, что это слишком сильно поможет, но может остановить рывковые повторные синхронизации, которые вы увидите в исходном алгоритме.

Ответ на комментарий:

Нет, клиенты по-прежнему будут сообщать серверу о своей позиции, но сервер не будет пытаться вычислить следующую позицию. Это будет означать, что сервер (и все остальные клиенты) будут отставать по крайней мере на один цикл отправки/получения.

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

Обнаружение читов можно даже отключить для повышения производительности или установить случайную проверку.

Примечание. Вся информация о столкновении / положении объектов в пределах диапазона перемещения должна быть отправлена ​​​​клиенту, чтобы это работало.

person Bill K    schedule 30.06.2009
comment
Разве серверу не пришлось бы постоянно получать и повторно отправлять тонны сообщений, если бы все клиенты должны были информировать всех других клиентов о своем текущем местоположении? - person Tom; 01.07.2009
comment
+1 На самом деле я собирался предложить то же самое. Это то, что делают многие популярные многопользовательские видеоигры. Сервер просто периодически следит за тем, чтобы все синхронизировались. (Я считаю, что игры Quake делают это.) - person Sasha Chedygov; 01.07.2009
comment
Что ж, мой первый вопрос остается в силе. Разве клиентам не придется постоянно отправлять тысячи сообщений, чтобы поддерживать сервер в актуальном состоянии на каждом шагу? Затем сервер снова отправляет эти данные всем игрокам поблизости. - person Tom; 01.07.2009
comment
«Тысячи сообщений постоянно» — это немного преувеличение, но нередко клиент уведомляет сервер о своем местоположении примерно 10 раз в секунду, а сервер передает большую часть этого обратно с той же скоростью. частая основа. - person Kylotan; 01.07.2009
comment
Кроме того, если вы отправляете на сервер 10 обновлений в секунду, вы можете игнорировать/пропускать некоторые из них здесь и там с небольшими побочными эффектами или вообще без них. - person Bill K; 01.07.2009

Я могу придумать 2 способа сделать это: заставить клиент выдавать команды серверу, и сервер будет основным хранителем карты.

Или держите карты в клиентах, и клиентам придется устанавливать соединения с другими клиентами, с которыми они «рядом», чтобы совершать движения, при этом ведение записей выполняется сервером и проверяется несколькими сверстниками (хакерская полиция).

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

person ryansstack    schedule 30.06.2009
comment
Интересно, но это ограничивает большие конфликты, поскольку P2P не может обрабатывать такое количество соединений одновременно — теперь вы также полагаетесь на соединение клиента для других клиентов. Я все еще ищу лучший сервер ‹› клиентскую систему. - person Tom; 01.07.2009
comment
Почему P2P не может обрабатывать много соединений? Каждый раз, когда кто-то что-то делает, нужна либо ретрансляция с сервера, либо сообщение от пира. Я думал, что трафик был примерно таким же (могу ошибаться). - person ryansstack; 09.07.2009

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

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

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

person AlbertoPL    schedule 30.06.2009
comment
Это не маленькая 2D игра. Он должен обрабатывать сотни игроков одновременно. Мне нужна максимально оптимизированная система. - person Tom; 01.07.2009
comment
хм, в этом случае придется настроить сервер так, чтобы он отправлял данные с достаточно малыми интервалами. Конечно, всем серверам потребуется какой-то лимит игроков, но, по крайней мере, добавьте 10-20 мс отставание на стороне движения клиента. Это едва заметно и в большинстве случаев должно соответствовать реальному положению игроков. - person AlbertoPL; 01.07.2009