-
Решил в игре реализовать возможность автоматической записи гонки с целью последующего её просмотра. Возник вопрос: достаточно ли каждый кадр запоминать только управление игрока (клавиши, которые он нажал)? Могу ли я затем снова запустить гонку с такими же исходными параметрами, восстанавливая только коды нажатых клавиш? Гарантировано ли, что гонка будет идти точно так же? В игре random не используется (всё зависит только от управления игрока). Знаю, что вопрос может показаться глупым. Но у меня возникли сомнения в том, что результаты операций с вещественными числами всегда одинаковы. Вдруг подведёт округление, и вместо того, чтобы нормально проехать, машина во что-нибудь врежется. :)
-
Если рандом не используется, то да. Только надо отдельно запоминать моменты нажатия и отжатия клавиш.
-
> Piroxyline (10.01.08 09:46) [1]
Большое спасибо.
-
> [2] AlexanderMS © (10.01.08 10:04)
Не верь тому, что написано в [1].
Смотри ситуацию: Игрок играет. У него фпс 200. На 100 кадре он нажимает влево, на 101 отпускает. Теперь повтор. Проигрывается с фпс 100. на 50 кадре отрабатывается нажатие, на 51 отпускаени... и что мы получаем? Мы получаем что машина едет влево дольше в два раза!!! Объяснять, чем это грозит - надо?
Есть несколько решений этой проблемы.. Я в свое время делал так: Делим секунду на 20 частей. Запоминаем положение и скорость машины в каждом отсчете(никаких нажатий клавиш, только состояние машины). Во время воспроизведения получаем некоторое текущее значение отсчета, например 21.7, получаем сплайн по трем точка(21,22,23), получаем положение и скорость машины в точке 21.7 Работает замечательно, и повторяемость гарантируема при любых данных.
-
Кстати, рандом тоже можно использовать, только нужно запоминать/восстаналивать RandSeed
-
@!!ex, интересно. Спасибо, а то я подумал, что мой вопрос вообще глупый. :) А если моменты нажатия/отжатия неважны, а имеет значение текущее состояние клавишы в данном кадре? Например (выполняется каждый кадр): Player.EngineOn := KeyPressed[Player.Index, Key_Gas];
Player.TurningLeft := KeyPressed[Player.Index, Key_Left];
Player.TurningRight := KeyPressed[Player.Index, Key_Right];
... Запомню каждый кадр либо массив KeyPressed, либо флаги EngineOn, TurningLeft и т. п., нормально будет?
-
> [5] AlexanderMS © (10.01.08 16:23)
Забудь о клавишах. Запоминай состояния. Поворот колесо, ускорение, и т.д. клавиши слишком ненадежный источник информации.
-
Спасибо, я понял.
-
С симуляторами понятно. Хотя при количестве объектов в несколько десятков и подробной симуляции - писать многие параметры объектов будет накладно. Например у автомобиля независимая подвеска и все 4 колеса имеют своё положение относительно корпуса автомобиля. И 5 раз в секунду писать все данные всех объектов?
А что на счёт стратегий? Писать в риплей команды юнитам? Или всё же ввод пользователя писать?
-
Бесполезно писать ввод пользователя!!! НЕЛЬЗЯ его писать. Тайминги при реплее не совпадут и будет большой десинх... А они не совпадут, гарантирую.
-
может просто записывать ротации и трансляции каждой машины? ну, или вектора движения (+остальной физики, если надо). при реплее, соотв-но, просто применять ротации и трансляции к машинам, с учётом "свободной" камеры.
-
> [10] grisme © (11.08.08 17:38)
Когда делал реплеи для самолета - записывал позицию и вращение с фиксированным таймингом(50 мс). И при воспроизведении просто получал нужное значение, если тайминг не кратный 50 мс, то просто интерполяцию проводил и получал положение машины. Вроде вполне адекватно получилось.
-
Если Update игровой механики происходит независимо от FPS то всё будет отлично работать, даже и с random'ом при сохранении изначального RandSeed. Всё это круто до тех пор пока не решишь сетевой код игры писать.
-
Выразился возможно неясно, разъясню: записи одного только ВВОДА пользователя вполне достаточно для воссоздания записи хоть 48-ми часовой игры, при условии что Update "независим" от FPS, т.е. количество вызовов Update при записи будет полностью соответствовать количеству вызовов при проигрывании независимо от конфигурации компьютера. Но в сетевой игре часто используются синхронизации позиций различными видами интерполяций, поэтому для записи демок сетевой игры (как и для самой сетевой игры) одного только ввода недостаточно. Вот типичный MainLoop игры с константным Updates Per Second (UPS):
dUPS := 1000 div UPS;
OldTime := Timer.Time - dUPS;
while not FQuit do
begin
while Timer.Time - OldTime >= dUPS do
begin
onUpdate;
inc(OldTime, dUPS);
end;
onRender;
end;
-
> [12] XProger © (13.08.08 04:18)
Даже в этом случае нужно очень постаратся, чтобы не получиться десинх... Например, если игра реагирует на нажатие немедленно, а записывается нажатие только в зависимости от Update Time, то может получится, некоторое различие по времени, что привдет к десинху. А если и реакцию на нажатие привязать к UpdateTime, то может создастся ощущение, что игра тормозит... Особенно будет заметно, если игрок привык кликать несколько десятков раз в секунду... Хотя это тема, конечно. Так работаю тповторы в Периметре, насколько мне известно.
-
Бесполезно писать ввод пользователя!!! НЕЛЬЗЯ его писать. Тайминги при реплее не совпадут и будет большой десинх... А они не совпадут, гарантирую.
В авиасиме ил2 используются оба подхода. Можно создать маленький компактный трек в котором только управляющие воздействия органов управления (проигрывается верно если нет изменения в моделях). Либо другой трек, куда пишутся все объекты и их расположение (проигрывается верно для любых версий моделей).
-
@!!ex, я считаю, что задачей Update как раз является обработка игровой логики, и соответственно ввода. DeltaTime в коде приведённом выше не нужен.
-
> [16] XProger © (15.08.08 14:16)
DeltaTime позволяет достичь большей четкости на мощных компах... А четкость нужна, особенно на чемпах.
-
> @!!ex © (10.01.08 10:15) [3]
Игрок играет. У него фпс 200. На 100 кадре он нажимает влево, на 101 отпускает. Теперь повтор. Проигрывается с фпс 100. на 50 кадре отрабатывается нажатие, на 51 отпускаени... и что мы получаем? Мы получаем что машина едет влево дольше в два раза!!! Объяснять, чем это грозит - надо?
не совсем понятно как в таком случае устроенна игра. по идее машина должна ехать не зависимо от кадров, да и время не кадрами должно отмеряется, а то будет как с досовскими играми запустил на современном компе и все несется со скоростью света.
вроде бы так должно быть:
> XProger © (13.08.08 04:18) [12] > Если Update игровой механики происходит независимо от FPS > то всё будет отлично работать, даже и с random'ом при сохранении > изначального RandSeed. > Всё это круто до тех пор пока не решишь сетевой код игры > писать.
я думал, что нужно хранить события и время между ними, но все никак не могу найти способа при проигрывании отмерять записанное время.
-
> не совсем понятно как в таком случае устроенна игра. по > идее машина должна ехать не зависимо от кадров, да и время > не кадрами должно отмеряется, а то будет как с досовскими > играми запустил на современном компе и все несется со скоростью > света.
ПОчему то есть желание написать матом... Но я помобю в себе это желание и разжую....
Машина едет нормально, а вот получает событие нажатия клавиши на несколько МС позже, чем она была нажата при игре.
|