Сохранение игры
Вначале важно понять, что сохранение игры во время выполнения — это сохранение динамического состояния, которое возникло в результате игрового процесса и поэтому сериализация это плохое решение.
Почему не сработает просто сериализовать сцену?
На первый взгляд, идея сохранить игру выглядит просто: взять все игровые объекты (gameobject) на сцене, записать их в файл и потом восстановить. К сожалению, этот подход фундаментально несовместим с архитектурой Unity и требованиями реальных проектов. Попытка его реализовать приведёт не к упрощению, а к поломке сохранений.
Из сохранения, Вы загружаете не состояние игры, а её «труп»
Вместо этого нужно научится восстанавливать gameobject из префаба
Когда вы сериализуете GameObject, вы фиксируете его текущее техническое представление в движке: координаты Transform, ссылки на компоненты, настройки MeshRenderer и BoxCollider. Подавляющие большинство этих данных - это статический декор, т.е. статические или технические свойства (коллайдеры, рендереры). Поэтому сериализовать их все — это гигабайты ненужных данных и минуты загрузки. Вместо этого нужно сохранять только состояние игры. Например, агент — это не его меш и коллайдер, а его имя, профессия, текущая цель и список задач. Восстанавливая только нужные для логики поведения данные мы не просто экономим, но делаем прозрачной модель игры.
Ссылки превратятся в «битые» указатели
Вместо этого нужно проиндексировать все объекты и после этого их пересвязать по индексам
В коде объекты ссылаются друг на друга: здание знает своего владельца (public Person owner). При наивной сериализации сохраняется ссылка на конкретный экземпляр объекта в памяти. После загрузки создаются совершенно новые экземпляры GameObject, и все старые ссылки указывают в никуда. Это гарантированный NullReferenceException и падение игры.
"Жизнь" в игре замрет
Вместо этого нужно снова подписаться на события и востановить ход игры
События не сериализуются, все объекты, которые ждут сигналов их не получат, и в лучшем случае замрут, а в худшем игра упадет. Агент, который ушел в здание, gameobject которого нет на сцене уже не появится, когда наступит момент уходить из здания.
Рейкаст должен замереть и продолжиться с того же места
Самое важное на этом этапе понять, что происходит в момент загрузки? Не продолжение, а реконструкция. Рейкаст замереть не может, запущенные короутины продолжают работать, управляющая логик и представляющие её классы, заменяться не будут. Отсюда у нас возникает задача выделить минимально возможное количество данных, которые нужно сохранить, чтобы при загрузке стало бы возможным реконструировать систему заново с прерванного момента.