Алгоритм клиент-серверных игр - PullRequest
15 голосов
/ 01 мая 2009

Для автономных игр основной игровой цикл (источник: 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 и т. Д.,

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

Ответы [ 6 ]

19 голосов
/ 01 мая 2009

Это было бы что-то вроде

Клиент:

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
12 голосов
/ 01 мая 2009

Клиент:

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 из одной из игр, в которой активно моддинговое сообщество. Изучение того, как это работает, даст хороший обзор того, как это следует сделать.

4 голосов
/ 01 мая 2009

Это действительно не простая проблема. На самом базовом уровне можно сказать, что сеть предоставляет те же данные, что и часть 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

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

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

3 голосов
/ 01 мая 2009

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

3 голосов
/ 01 мая 2009

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

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
}
1 голос
/ 27 марта 2013

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

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

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

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

tldr; прочитайте это.

...