Pull to refresh

Comments 17

Кроме Braid время можно отматывать ещё в эмуляторах ретро-консолей и в некоторых отладчиках.

Делаю виртуальную машину с отмоткой времени и вижу только два варианта:

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

2 Прогонять программу с самого начала до "текущее состояние минус одна инструкция"

Подумал, что первый вариант бьёт по производительности (лишние действия при работе кода) и требует очень много памяти, и выбрал второй вариант. Чем дальше от начала программы, тем дольше происходит перемотка на одну инструкцию назад. Но можно ускорить, делая снимки памяти и при перемотке прогонять с них. Также можно взять немного от первого варианта, сохраняя данные последних N инструкций, чтобы при перемотке назад моментально исполнялись эти сохранённые шаги, пока на фоне программа исполняется с начала/снимка, что требует время. Сохранённые шаги скрывают этот лаг.

Наверно, тут большое поле для оптимизаций, поэтому давно ищу материал как это делается в подобных системах, но не найду. Может кто встречал?

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

Я как-то делал покадровую перемотку видео назад в своей программе - надо было найти предыдущий ключевой кадр, а от него на нужное количество кадров пройти вперёд.

Да, это оно. Я ещё не дошёл до снимков, так как задержка перемотки назад пока комфортная, не дошла и до секунды.

Пытаетесь сделать альтернативу rr (site)?

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

Из ААА это одна из ключевых механик принцов персии от юбисофт. В 00е было топ.

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

Кстати, была ещё версия для GBA.

6 лет назад я для блокчейнов нечто такое делал. Там была задача агрегировать данные, приходящие из блоков. Они попутно обрабатывались, менялись, после складывались в MongoDB. Но был нюанс - мог произойти форк данных. Тогда нужно откатить назад несколько блоков и пойти по новой цепочке, записать другие данные.

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

Сам микро-язык был по суть JSON, прям в таком виде в MongoDB и хранилось, в отдельной коллекции.

Не везде применимый, но очень практичный был способ - ни единой проблемы.

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

Вспомнилось про https://en.wikipedia.org/wiki/Netcode#Rollback

Применяется в файтингах. Вместо того, чтобы ждать данные от противника и мучиться от лагов картинки и геймплея, движок игры всё время предсказывает поведение удалённого противника и локальный игрок дерётся с этим его "призраком". Как только поступающие данные указывают, что движок не угадал, он тут же перематывает состояние игры назад и ускоренно проигрывает его (рендерить картинку не надо, только внутреннее состояние) с правильными данными. Т.е. он ещё всё время записывает и хранит ввод локального игрока, чтобы при этом проигрывании дрались два потока ввода двух игроков. В итоге локальный игрок увидит резкое изменение картинки. Обычно, это телепорт противника. Я сам ещё не играл, но это выглядит явно лучшим компромиссом, чем замедлённо-тормознутая игра.

Кстати, именно с добавлением этой системы я связываю изменение геймплея последних трёх частей Mortal Kombat. Они стали каким-то вязкими, замедлёнными. Потому что такую скорость легче предсказывать и корректировать. В таком темпе в принципе невозможен внезапный резкий бег вперёд на противника как было в UMK3, потому что это большое расстояние, и если его не предсказать, то при корректировке противник телепортируется на это большое расстояние.

Собственно, а вопрос из заголовка не раскрыт. Как устроен braid? Какой из механизмов там использован? Кликбейтный заголовок не соответствует статье.

Полностью согласен. Человек придумал себе реализацию отмотки времени, и думает что все работает именно так, как он себе придумал.

Я думал увижу реальную реализацию, а не то, что смог бы сам набросать за вечер.

Есть много видео, где сам Блоу рассказывает о том, именно эти вещи сделаны, без кода, просто концептуально, но достаточно подробно. Недавно у него была серия стримов вместе с Кейси Муратори, как раз про Брейд

Клёвая статья. Хотелось бы увидеть такой же разбор по uter wilds где вся солнечная система работает в реальном времени.

Наверное, одних из самых загадочных в плане «как это вообще сделали» миров в Braid — это четвёртый.
Почитать что-то с кодом про то, как перемещение во времени вперёд привязано к передвижению Тима вправо, и каким забавным и неожиданным последствиям это приводит — было бы невероятно интересно.

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

Sign up to leave a comment.

Articles