Games

Постоянные данные: Как сохранить состояния и настройки игры

BRONSON ZGEB / UNITY TECHNOLOGIESSenior Content Developer
Feb 23, 2021|10 Мин
Постоянные данные: Как сохранить состояния и настройки игры
Эта веб-страница была переведена с помощью машинного перевода для вашего удобства. Мы не можем гарантировать точность или надежность переведенного контента. Если у вас есть вопросы о точности переведенного контента, обращайтесь к официальной английской версии веб-страницы.

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

Обновлено 23 июня 2021 г: В рамках Unite Now 2020 я организовал сессию с советами по сохранению данных в Unity. Здесь описаны некоторые из распространенных способов сохранения и загрузки данных в проекте Unity, но это далеко не полный список. Иными словами, существует больше способов сериализации данных, чем Вам когда-либо понадобится, и каждый подход решает определенную проблему и имеет свой собственный набор сильных и слабых сторон. В этом блоге мы рассмотрим те же общие методы, которые я обсуждал на сессии Unite Now.

PlayerPrefs

PlayerPrefs не предназначены для сохранения игровых состояний. Тем не менее, они полезны, поэтому мы их обсудим. Вы можете использовать PlayerPrefs для хранения предпочтений игрока между сессиями, например, настроек качества, громкости звука или других несущественных данных. PlayerPrefs хранятся где-то на Вашем устройстве, отдельно от Вашего проекта. Точное местоположение зависит от Вашей операционной системы, но обычно это место, которое доступно во всем мире и управляется Вашей ОС. Данные хранятся в виде простых пар ключ-значение. Из-за легкости доступа они не защищены от пользователей, которые захотят открыть и изменить их, и их можно случайно удалить, поскольку они сохраняются вне проекта и управляются Вашей ОС.

PlayerPrefs относительно просты в реализации и требуют всего несколько строк кода, но они поддерживают только значения типа Float, Int и String, что затрудняет сериализацию больших сложных объектов. Целеустремленный пользователь может преодолеть это ограничение, преобразовав сохраненные данные в формат, представленный одним из этих базовых типов, но я не рекомендую этого делать, поскольку существуют лучшие инструменты для хранения Ваших данных.

public void SavePrefs()
{
    PlayerPrefs.SetInt("Volume", 50);
    PlayerPrefs.Save();
}
 
public void LoadPrefs()
{
    int volume = PlayerPrefs.GetInt("Volume", 0); 
}

Наконец, поскольку каждое приложение Unity хранит все свои PlayerPrefs в одном файле, оно не очень хорошо подходит для работы с несколькими файлами сохранения или облачными сохранениями, которые требуют, чтобы Вы хранили и получали данные сохранения из другого места.

JSON

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

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

JsonUtility

JsonUtility - это встроенный в Unity API для сериализации и десериализации данных JSON. Как и PlayerPrefs, он также относительно прост в реализации. Однако, в отличие от PlayerPrefs, Вы должны сами сохранить данные JSON в файл или по сети. Самостоятельное хранение данных упрощает управление несколькими файлами сохранения, поскольку Вы можете хранить каждый файл в отдельном месте. Чтобы сделать это проще, я написал базовый файловый менеджер, который доступен в этом репозитории примеров.

Важно отметить, что JsonUtility не является полнофункциональной реализацией JSON. Если Вы привыкли работать с данными JSON, Вы можете заметить отсутствие поддержки определенных функций. Если Вам интересно сравнить производительность различных JSON-решений, попробуйте этот проект бенчмаркинга. Помните, что лучше всего тестировать на целевом устройстве, если это возможно.

На JsonUtility накладываются те же ограничения, что и на внутренний сериализатор Unity - то есть, если Вы не можете сериализовать поле в Инспекторе, Вы не сможете сериализовать его в JSON. Чтобы обойти эти ограничения, Вы можете создать типы данных Plain Old Data (или PODS) для хранения всех Ваших сохраненных данных. Когда придет время сохранять, перенесите данные из их типов выполнения в POD и сохраните их на диск. При необходимости Вы также можете создать пользовательские обратные вызовы сериализации для поддержки типов, которые сериализатор Unity не поддерживает по умолчанию.

К теме JsonUtility, EditorJsonUtility - это еще один полезный инструмент. В то время как JsonUtility работает с любым объектом на основе MonoBehaviour или ScriptableObject, EditorJsonUtility будет работать с любым типом движка Unity. Таким образом, Вы можете создать JSON-представление любого объекта в редакторе Unity - или пойти в другом направлении и создать актив из JSON-файла.

Другие библиотеки

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

Бинарные инструменты

  • MessagePack - это эффективный двоичный сериализатор. Она производительна и относительно проста в использовании. Как и JSON, он доступен практически на всех платформах, поэтому Вы можете использовать его для передачи данных по сети для связи с внутренними серверами. Подробнее об этом Вы можете прочитать здесь.
  • ProtoBuf и Protobuf-net - еще один похожий бинарный сериализатор. Это также быстро и эффективно. Google разработал его как производительную альтернативу существующим форматам, таким как XML. Как и JSON и MessagePack, он также хорошо подходит для общения по сети.
  • BinaryFormatter - это библиотека DotNet для прямого хранения Ваших объектов в двоичном формате. Однако BinaryFormatter имеет опасные уязвимости в системе безопасности, поэтому его следует избегать. Повторяю, не используйте BinaryFormatter. Узнайте больше о рисках безопасности здесь.

Текстовые инструменты

  • EasySave - это хорошо поддерживаемый и популярный плагин, доступный в Unity Asset Store. Он позволяет сохранять все Ваши данные без написания какого-либо кода, что отлично подходит для новичков. Кроме того, у него мощный и гибкий API, что делает его идеальным для опытных пользователей. Он не бесплатный, но он стоит того, если Вы ищете полнофункциональное решение из коробки.
  • JSON.Net - это бесплатная реализация JSON с открытым исходным кодом для всех платформ DotNet. В отличие от встроенной JsonUtility, она является полнофункциональной. Однако за это приходится расплачиваться, поскольку его производительность значительно ниже, чем у встроенной JsonUtility. Стандартная версия не поддерживает все платформы Unity, но в Unity Asset Store доступна модифицированная версия, которая добавляет поддержку.
  • XML - это альтернативный формат данных. Как и JSON, он относительно понятен человеку и имеет некоторые особенности, которые могут быть полезны для Вашего конкретного приложения, например, пространства имен. DotNet имеет встроенную поддержку XML.
Безопасность данных

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

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

Более подробную информацию о сериализации Вы можете найти на странице руководства. Если Вы хотите увидеть это в действии, посмотрите сопутствующую сессию Unite Now.