Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Многопользовательская игра реального времени - нужен совет (http://www.flasher.ru/forum/showthread.php?t=127976)

Gaen 27.07.2009 13:36

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

Пока думаю обмениваться сообщениями о нажатии и отпускании клавиш:
1. юзер нажимает кнопку (например газ), его корабль начинает газовать
2. на сервер уходит сообщение о том, что юзер включил газ, плюс его текущие координаты плюс локальный таймстамп (зная разницу во времени с сервером, можно вычислить время нажатия по серверным часам)
3. сервер запоминает что этот кораблик включил газ, шлет подтверждение и рассылает остальным клиентам сообщение о том что этот корабль включил газ (плюс координаты, таймстамп, все дела)
4а. клиент получает подтверждение, все ок, процесс продолжается
4b. клиент не получает подтверждение... тогда получается что юзер будет видеть газующий кораблик, пока клиент не получит новую порцию данных с сервера, в том числе о своих координатах и скорости, и тогда для юзера его кораблик встанет на реальное место и перестанет газовать. Чтобы включить газ, нужно будет отпустить кнопку газа и нажать снова.

Насчет отпускания - алгоритм тот же.

Какие плюсы и минусы у такого подхода? Какие ещё могут быть варианты? Что можно почитать по теме? (Статью Касперски читал, там несколько не то, это скорее обзорная статья по способам организации сети)

BlooDHounD 27.07.2009 13:42

1. зачем он начинает газовать?
2. зачем отправляется что-то кроме вектора направления?
4b. этот пункт лишний.

iflamberg 27.07.2009 13:45

искать по словам:
Dead Reckoning
Latency Hiding for Networked Games
lag compensation
latency compensation

собственно во отличная статья на тему http://www.gamasutra.com/features/19...aronson_01.htm

Замечу так же, что для первой простенькой игрушки можно не заморачиваться и просто передавать вектор или перемещение. Иначе можно запутаться, нагрузить кодом и впасть в прострацию =)

Gaen 27.07.2009 15:19

Спасибо за ответы.

BlooDHounD

Цитата:

1. зачем он начинает газовать?
Чтобы сдвинуться с места :)

Цитата:

2. зачем отправляется что-то кроме вектора направления?
Пытаюсь найти способ не гонять лишних данных. Хотя если народу будет много, события нажатия/отпускания будут происходить чаще, чем игровые тики. Мысль ясна.

Цитата:

4b. этот пункт лишний.
Ок, если слать только вектора, думаю подтверждения станут не нужны.

iflamberg, спасибо за наводки

BlooDHounD 27.07.2009 15:22

1. что бы сдвинуть с места ждите 4a
2. при это собираетесь слать кучу фигни, которая и так должна быть на сервере?

AlexStukoff 27.07.2009 16:21

Координаты, вектор направления, скорость корабликов хранятся только на сервере!
Сервер принимает:
- нажатие влево/вправо (один бит)
- нажатие/отпускание газа (еще один бит)
Сервер отдает:
- только изменившиеся с последнего вызова координаты и вектора направлений корабликов.

всё. остальное. на. сервере.

в итоге программная часть клиента сведется к 100 строкам кода :) :) :)

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

iflamberg 27.07.2009 16:42

На сервере все данные должны поверяться, чтобы хаков небыло. А то, можно нажатие влево-вправо передавать не 30 раз в секунду, а 100 и разворачиваться в 3 раза быстрее.

Програмная часть не сведется к 100 строчкам кода. Потому что свой "кораблик" и "кораблик" противника должен двигаться независимо от того, опаздывают данные или нет(а в флеш реализован только tcp/ip сокет, это значит что задержки будут от 70мс и выше). Иначе будут двигаться рывками. Для этого и применяются алгоритмы сглаживания.

Gaen 27.07.2009 16:52

AlexStukoff, полностью согласен, кроме 100 строчек :)

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

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

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

Вопрос: какая частота пересчета данных на сервере приемлема для такой игры? 2 раза в секунду - хватит?

AlexStukoff 27.07.2009 17:06

можно передавать и будут передавать :) Левые сервер реджектит, это нормальная практика. А вот развернутся в 3 раза быстрее уже не удастся, ибо вектор вычисляется на сервере на основании только валидных сигналов разворота.

Что делать с рыками и сглаживанием - это отдельная тема. В самом простом случае - полагаем что кораблик двигается туда, куда он двигался и раньше, пока не поступят новые данные с сервера.
Правда в этом случае возможны неприятные фишки формата "кораблик летит вверх и вдруг- БАЦ -и он уже летит влево да еще и прыгнул пикселов на 10-20" :(

Но в целом по вопросу борьбы с лагами я склоняюсь перед вашим iflamberg авторитетом :) ;)

BlooDHounD 27.07.2009 17:16

GAIKER, круто. делайте так :) потом будите думать как сделать мультиплэйер :) а то в вашей игре, каждый пользователь будет играть в свой кораблик. остальные всегда будут двигаться как попало и с неизвестным отставанием. если этим можно пренебречь, тогда - да. а если у Вас кораблик не умеет стрелять спиной, и должен стрелять всегда перед собой, и угол нужен при расчётах попадания, тогда Ваша идея утопична, так как пользователи будут стрелять во врагов, которых уже давно "там" нет.

iflamberg 27.07.2009 17:24

О какой потере данных вообще речь? У нас tcp/ip соединение, никаких потерь, только следующий пакет не передается пока не пришло подтверждение о доставке предыдущего, что приводит к лагам в 100мс.

2BloodHound. Именно так и делают. Иначе на экране будут подвисшие изображение по 300мс.
См., например, http://www.kongregate.com/games/DJSt...isputed-galaxy - достаточно частые случаи, когда стреляешь ты стреляешь, а потом дерг - противник совсем в другом углу.

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

Gaen 27.07.2009 17:44

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

BlooDHounD 27.07.2009 18:38

iflamberg, подвисшие на 300 мс o_0? ну тут скорее дело в кривизне сервера, чем в недостатке предсказаний.

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

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

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

принцип простой на самом деле:
1. синхронизируется время с точностью до 100 миллисекунд между сервером и клиентом
2. всё действия, которые должны выполнять игроки, сервер посылает вместе со временем, в которое они должны эти действия закончить.
3. все расчёты на клиенте проводятся относительно серверного времени
4. получаем систему, которая показывает в реальном времени, что сейчас происходит на сервере, с точностью до 100 миллисекунд.
5. чтобы добиться плавности и сгладить задержки сети, мы самостоятельно рассчитываем скорость исходя из текущих и конечных данных. будут получаться не большие ускорения/замедления незаметные игроку. что бы сгладить ответ сервера, мы можете, например, начать поворачивать Ваш кораблик, или сделать анимационную фиговинку под курсором, что бы отвлечь пользователя на 200 миллисекунд, пока сервер будет отвечать :)

таким образом при СИЛЬНОМ лаге, у Вас все кораблики очень быстро прилетят к своим точкам, а не телепортнуться, и пользователь будет видеть, что произошло, а не пытаться врубиться, откуда это всё взялось. не будет писать багрепорты, что он стрелял в кораблик и не попадал, а его застрелил кто-то невидимый в спины.

Gaen 27.07.2009 20:05

BlooDHounD, как бы вам объяснить, чтобы вы меня наконец поняли.

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

Вы описываете систему, в которой всё синхронно с точностью до 100 миллисекунд. Пока закроем глаза на то, что это это значит 10 раз в секунду принимать данные от каждого клиента, пересчитывать поле и рассылать всем клиентам новые данные.

Цитата:

Всё действия, которые должны выполнять игроки, сервер посылает вместе со временем, в которое они должны эти действия закончить.
Цитата:

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

Если я вас правильно понял, то вы предлагаете такую систему:
1. Игрок А начинает движение и извещает об этом сервер
[проходит время]
2. Сервер получает сообщение, ждет конца таймаута и пересчитывает поле
3. Сервер рассылает клиентам обновленные данные
[проходит время]
4. Игрок Б получает сообщение
5. Клиент игрока Б начинает двигать корабль А. Хотя реально к этому моменту корабль А уже двигался в течение какого-то времени, и находится не там, где его видит игрок Б. Более того, игрок Б получает оповещение о собственном движении тоже с задержкой, и видит себя не в том месте, где он сейчас реально находится.

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

Цель всего этого - построить систему, которая сможет оставаться синхронной на больших пингах.

BlooDHounD 27.07.2009 20:19

это Вы меня не поняли.

никаких данных 10 раз в секунду нету. есть синхронное время сервера и клиента.

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

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

я предлагаю такую схему:
1. игрок А хочет начать движение и извещает об этом сервер
2. сервер ждет конца таймаута и пересчитывает поле ( вот тут как бы дело ваше. я бы сразу считал, тогда нагрузка на сервер была бы распределена по мере поступления данных, а не пиково в моменты тиков )
3. сервер рассылает клиентам обновленные данные
[проходит время] ( с нормальным нетом ~20-50 миллисекунд )
4. игрок Б получает сообщение ( как и игрок А, практически в одно и тоже время )
5. клиент игрока Б начинает двигать корабль А, ровно в тот момент, в который это начинает и делать и игрок А.
6. корабль игрока А начинает двигаться на обоих машинах практически одновременно, и двигается он синхронно.

кстати у нас в дестени время синхронизируется обычно с точностью до 10-20 мс. в локальной сети до 2-4 мс.

Gaen 27.07.2009 22:22

Цитата:

1. игрок А хочет начать движение и извещает об этом сервер
2. сервер ждет конца таймаута и пересчитывает поле ( вот тут как бы дело ваше. я бы сразу считал, тогда нагрузка на сервер была бы распределена по мере поступления данных, а не пиково в моменты тиков )
3. сервер рассылает клиентам обновленные данные
[проходит время] ( с нормальным нетом ~20-50 миллисекунд )
4. игрок Б получает сообщение ( как и игрок А, практически в одно и тоже время )
5. клиент игрока Б начинает двигать корабль А, ровно в тот момент, в который это начинает и делать и игрок А.
6. корабль игрока А начинает двигаться на обоих машинах практически одновременно, и двигается он синхронно.
Предельно ясно, нет вопросов.
В этом подходе меня смущало то, что все-таки существует постоянная задержка, хоть и незначительная. Но главное, я наконец полностью осмыслил, что же пытался сказать :) Метод позволит большую часть времени держать синхронизацию теоретически идеальную, она будет немного нарушаться только при изменении вектора скорости. Вместо незначительной задержки мы получим незначительные корректировки координат, скорости и ускорения.
Насчет того, когда пересчитывать - зависит от. Если висит скажем 5 клиентов, то выгоднее пересчитывать сразу при получении данных. Если их сотня, то лучше собрать команды, которые они наприсылали, и обсчитать всё пачкой.

Цитата:

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

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

Что вы имеете в виду под действием?

BlooDHounD 27.07.2009 22:53

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

Gaen 27.07.2009 22:56

например?

BlooDHounD 27.07.2009 23:06

идти, туда, и быть там во столько-то

Gaen 27.07.2009 23:29

Твою ж ты мать)
С rts все проще, сказал идти в другой конец карты, сообщил об этом серверу, он это дело разослал, а дальше ai на клиентах уже всё выполняет абсолютно одинаково и соответственно синхронно.

Я хочу сделать именно живое управление кораблем. Играли может в такую старую игрушку Roketz?

BlooDHounD 27.07.2009 23:32

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

Gaen 28.07.2009 00:37

Так оно и будет. Только без точки, просто продолжается движение с тем же вектором скорости (и возможно ускорения).

BlooDHounD 28.07.2009 07:38

GAIKER, удачи. Вам говоришь: "А", а вы отвечаете: "да, А, но ЗЕЛЁНОЕ!"

Gaen 28.07.2009 12:34

BlooDHounD, большое спасибо.


Часовой пояс GMT +4, время: 23:19.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.