Войти
dconvertСтатьи

Почему для сохранения игр использование сериализации плохая идея?

Автор:

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

Рассмотрим пример. У нас есть здание – класс Building, которое имеет размер Size = 1, 2, 3 … Это здание состоит из блоков – класс Block, и их количество рассчитывается методом Create() на основании размера. Для простоты пусть так: BlockCount = Size*Size. Далее каждая сторона блока (класс BlockSide) может иметь разный тип SideType, например, дерево, металл, бетон. А так же текущий износ (Wear). А каждый тип имеет свои характеристики, например, прочность (Strenght). В этом примере, постоянными величинами будет Strenght, расчетными BlockCount, и динамическими Size, SideType, Wear.

Если мы пользуемся префабами в Unity, то её сериализация позволяет формировать достаточно сложные взаимосвязи из постоянных характеристик объектов. Например, мы можем подготовить префаб BuildingPrefab с компонентом Building, у которого будет дочерний префаб BlockPrefab с компонентом Block, и, кроме того, он будет содержать компоненты визуализации (MeshRendering). Он будет лишь образцом для создания строения из блоков после расчета в методе Create(). Таким образом, на старте игры у нас уже построено здание путем клонирования префабов. Далее в течении игры игрок будет развивать здание, например, задавая типы сторонам блоков, что мы будем фиксировать, подгружая в дочерние объекты SidePrefab постоянную информацию о них, такую как Strenght. Причем динамическими значениями будет управлять разная логика – Size сможет изменять сам игрок, делая апгрейд, SideType настраивая здание, а Wear будет изменяться некоторой логикой внешней среды.

К тому моменту, когда игрок захочет сохранить свое здание, оно уже потеряет свое компактное представление (оптимальное в смысле хранения данных в 3-ей нормальной форме) из постоянных префабов и у нас есть два пути:

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

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

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

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

8 мая 2021