Comments 13
Спасибо, очень интересно.
А не лучше ли использовать LinkedList вместо ArrayList? Выполняются частые операции вставки и удаления, доступ к произвольному элементу не требуется.
А как быть в более сложных случаях, когда есть физика? Например, игрок сталкивает коробку и она падает. Если аналогично записывать и воспроизводить положение и поворот, не возникнут ли проблемы при принудительной установке положения Rigid Body объектам? Вроде слышал, что в юнити это плохо сказывается на производительности.
Для состояний т.к. их может быть много (жизни, предметы и пр.), но при этом обычно на новом «кадре» меняются лишь некоторые (а восстанавливать хочется точно), то без выборочного дельта-кодирования в битовый/байтовый поток оказывается не обойтись т.е. кодировать для каждого «кадра» только те состояния, которые изменились и тратить на это минимум памяти в зависимости от величины изменения.
Ну и следующий логичный шаг — чтобы не заниматься сравнением конечных значений легче будет писать изменения в «поток изменений» в том же месте кода, где значение меняется. А тут уже и до сериализации в виде do/undo потоков недалеко, чтобы вообще не делать изменений напрямую.
Мне кажется, для такого подхода Unity вообще плохо подходит, так как там смешаны в кучу состояние объекта, его графическое представление и физическая модель.
Помню, писал это всё вручную — физика считалась со своим фиксированным шагом, при рисовании интерполировал (или экстраполировал) состояния. Вот там перемотку времени очень просто было бы сделать.
Правда, хранить цепочку состояний можно только для мира с небольшим количеством сущностей.
Если объект сцены создаётся динамически, либо если объект загружается из сохраненной игры, то ему прописывают ID из менеджера в одну из компонент при его создании. Если объект загружается вместе с Unity-сценой, то ID у него будет не прописан и он может автоматически зарегистрироваться в менеджере, который присвоит ему новый ID.
Также можно дополнительно прописывать некоторые PersistentID'шки в объектах на сцене Unity, чтобы они связывали своё состояние всегда с определенными записями в БД (скажем, для онлайн игр или игр вроде Dark Souls без нормальных сейвов).
Плавно перематывать назад по записанным данным ввода можно будет только дискретные действия, например, четкое передвижение на клетку вверх/влево/вправо/вниз, или простое ожидание. А вот всякие цепочки последствий от, в общем случае, необратимых взаимодействий таким образом перемотать сложно т.к. нужно тогда делать ключевой кадр (snapshot) в прошлом и постоянно доматывать от него до нужного кадра в будущее, что может быть слишком медленно. Это как играть видео назад в видеоплеере из упакованного инкрементального формата.
Ввод хорошо использовать для реплеев при детерминированной механике в т… ч. идентично настроенных генераторах случайных чисел. Скажем, реплеи для игр типа Clash of Clans занимают минимум места, там просто указано в какой момент какие команды задействовал игрок, но они привязаны к версии механики игры, которую нужно тем или иным образом стараться не сломать в новых версиях (записывать версию в реплей и уметь играть механику старых версий, либо просто не играть старые реплеи).
Prince of Persia: The Sands of Time стала одной из первых игр со встроенной в геймплей механикой перемотки времени.
А как же "Последний Экспресс" ещё под Windows 95?
Система перемотки времени в стиле Prince of Persia