Алгоритм для клиент-серверных игр

Для автономных игр основной игровой цикл (источник: wikipedia)

while( user doesn't exit )
  check for user input
  run AI
  move enemies
  resolve collisions
  draw graphics
  play sounds
end while

Но что, если я разрабатываю клиент-серверные игры, такие как Quake, Ragnarock, Trackmania и т.д.,

Что такое Loop/Algorithm для клиентских и серверных частей игры?

Ответы

Ответ 1

Это будет что-то вроде

Клиент:

while( user does not exit )
    check for user input
    send commands to the server
    receive updates about the game from the server
    draw graphics
    play sounds
end

Сервер:

while( true )
    check for client commands
    run AI
    move all entities
    resolve collisions
    send updates about the game to the clients
end

Ответ 2

Клиент:

connect to server
while( user does not exit && connection live)
    check for user input
    send commands to the server
    estimate outcome and update world data with 'best guess'
    draw graphics
    play sounds
    receive updates about the game from the server
    correct any errors in world data
    draw graphics
    play sounds
end

Сервер:

while( true )
    check for and handle new player connections
    check for client commands
    sanity check client commands
    run AI
    move all entities
    resolve collisions
    sanity check world data
    send updates about the game to the clients
    handle client disconnects
end

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

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

Также существует множество проблем, связанных с разделением разделов этих процессов на отдельные потоки для оптимизации времени отклика.

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

Ответ 3

Это действительно не простая проблема. На самом базовом уровне вы можете сказать, что сеть предоставляет те же данные, что и элемент MoveEnemies в исходном цикле. Поэтому вы можете просто заменить свой цикл:

while( user doesn't exit )
  check for user input
  run AI
  send location to server
  get locations from server
  resolve collisions
  draw graphics
  play sounds
end while

Однако вам нужно учитывать задержку, поэтому вы не хотите приостанавливать свой основной цикл вызовами в сети. Чтобы преодолеть это, нет ничего необычного в том, что сетевой движок сидит во втором потоке, опроса для данных с сервера как можно быстрее и размещения новых местоположений объектов в пространстве общей памяти:

while(connectedToNetwork)
    Read player location
    Post player location to server
    Read enemy locations from server
    Post enemy locations into shared memory

Тогда ваш основной цикл будет выглядеть так:

while( user doesn't exit )
  check for user input
  run AI
  read/write shared memory
  resolve collisions
  draw graphics
  play sounds
end while

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

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

while (PlayerConnected)
    Wait for player to post location
    Place new location in shared memory

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

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

Ответ 4

Клиентская часть в основном такая же, за исключением замены

run AI
move enemies
resolve collisions

с

upload client data to server
download server updates

И сервер просто делает:

while (game is running)
{
    get all clients data
    run AI
    resolve collisions
    udpate all clients
}

Ответ 5

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

Ответ 6

Очень полезно, и я хотел бы утверждать, что следующая статья: Архитектура клиент-сервер

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

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

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

TL;DR; прочитайте его.