Как сохранить игру unity android

Обновлено: 01.05.2024

Главная » Как сохранять и загружать данные игры в Unity

Как сохранять и загружать данные игры в Unity

Узнайте, как сохранять и загружать игру в Unity с помощью PlayerPrefs, Serialization и JSON. Дополните свой пользовательский опыт знаниями о том, как сохранять и загружать данные.

Но как создать файл сохранения и что в нем должно быть? Вам также нужно использовать файл сохранения, чтобы отслеживать настройки игрока? Как насчет отправки сохранений в интернет, чтобы их можно было позже загрузить на другое устройство?

В этом уроке вы узнаете:

  • Что такое сериализация и десериализация.
  • Что такое PlayerPrefs и как его использовать для сохранения настроек игрока.
  • Как создать файл сохранения игры и сохранить его на диск.
  • Как загрузить файл сохранения игры.
  • Что такое JSON и как его использовать.

Приступая к работе

Скачайте стартовый проект вверху страницы. Вы будете реализовывать код для сохранения и загрузки игры, а также логику сохранения настроек игроков.

Важные концепции сохранения

Есть четыре ключевых концепций сохранения в Unity:

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

Схема использования сериализации в Unity

Десериализация: это именно то, на что похоже. Это противоположность сериализации, а именно преобразование потока байтов в объект.

Player Prefs

Откройте проект, затем откройте сцену с именем Game и нажмите на кнопку воспроизведения.

Чтобы начать игру, нажмите на кнопку New Game. Чтобы воспроизвести игру, вы просто перемещаете мышь, и пистолет будет следовать за вашим движением. Нажмите левой кнопкой мыши, чтобы выстрелить и поразить цели (которые переворачиваются вверх и вниз через различные промежутки времени), чтобы получить игровой счет. Попробуйте и посмотрите, какой счет вы сможете набрать за тридцать секунд. Чтобы вызвать меню в любое время, нажмите кнопку esc на клавиатуре.

Какой бы забавной ни была эта игра, без музыки она могла бы быть немного суховата. Вы могли заметить, что есть переключатель музыки, но он был выключен. Нажмите на play, чтобы начать новую игру, но на этот раз установите переключатель Music на включенное положение, и при запуске игры вы услышите музыку. Убедитесь, что колонки компьютера включены!

Изменить настройки музыки было просто, но нажмите на кнопку воспроизведения еще раз, и вы заметите проблему: музыка больше не проверяется. Несмотря на то, что вы меняли настройки музыки ранее, это изменение не отслеживалось. Это то, в чем PlayerPrefs преуспевает.

Создайте новый скрипт с именем PlayerSettings в папке Scripts. Поскольку вы будете использовать некоторые элементы пользовательского интерфейса, добавьте следующую строку вверху файла с другими пространствами имен:

Затем добавьте следующие переменные:

Они будут отслеживать объекты Toggle и AudioSource.

Затем добавьте следующую функцию:

После настройки скрипт будет:

  1. Проверять, есть ли в PlayerPrefs кэшированная настройка для ключа «music». Если там нет значения, он создает пару ключ-значение для музыкального ключа со значением 1. Он также включает переключатель и включает AudioSource. Это будет запущено при первом запуске игры. Значение 1 используется, потому что вы не можете сохранить логическое значение (но вы можете использовать 0 как false и 1 как true).
  2. Проверять ключ «music», сохраненный в PlayerPrefs. Если значение установлено на 1, в проигрывателе была музыка, поэтому он включает музыку и устанавливает переключатель в положение «включено». В противном случае он отключает музыку и переключатель.

Теперь сохраните изменения в скрипте и вернитесь в Unity.

Добавьте скрипт PlayerSettings в игровой объект Game. Затем разверните игровой объект UI, а затем игровой объект Menu, чтобы открыть его дочерние элементы. Затем перетащите игровой объект Music в поле Toggle скрипта PlayerSettings. Затем выберите игровой объект Game и перетащите AudioSource в поле MyAudio.

Настройка параметров скрипта PlayerSettings в окне Inspector редактора Unity

Музыка настроена на работу при запуске игры (поскольку в функции Awake есть код), но вам все равно нужно добавить код, если игрок изменяет настройки во время игры. Откройте скрипт PlayerSettings и добавьте следующую функцию:

Это почти то же самое, что и код, который вы написали ранее, за исключением одного важного отличия. Он проверяет состояние переключателя музыки, а затем соответствующим образом обновляет сохраненную настройку. Чтобы этот метод был вызван и, следовательно, чтобы он мог выполнять свою работу, вам необходимо установить метод обратного вызова для игрового объекта Toggle. Выберите игровой объект Music и перетащите игровой объект Game на поле объекта в разделе OnValueChanged:

Установка функции-обработчика для кнопки переключения в окне Inspector редактора Unity

Выберите раскрывающийся список, в котором сейчас указано No Function, и выберите PlayerSettings -> ToggleMusic (). Когда кнопка переключения в меню нажата, она вызывает функцию ToggleMusic.

Выбор метода для обработки события нажатия кнопки в окне Inspector редактора Unity

Теперь у вас есть все необходимое, чтобы отслеживать настройку музыки. Нажмите Play и попробуйте, включив или выключив переключатель музыки, затем завершите сеанс воспроизведения и начните новый сеанс воспроизведения.

Теперь настройки музыки сохранены правильно! Отличная работа, но возможности сериализации только начинаются.

Сохранение игры

Использовать PlayerPrefs было довольно просто, не так ли? С его помощью вы сможете легко сохранить в нем другие настройки, такие как графические настройки плеера или информацию для входа (например, токены Facebook или Twitter), а также любые другие настройки конфигурации, которые имеет смысл отслеживать для игрока. Однако PlayerPrefs не предназначен для отслеживания сохраненных игр. Для этого вы захотите использовать сериализацию.

Первым шагом к созданию файла сохранения игры является создание класса файла сохранения. Создайте скрипт с именем Save и удалите наследование MonoBehaviour . Удалите также стандартные методы Start () и Update () .

Затем добавьте следующие переменные:

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

Вам нужно добавить еще один очень важный фрагмент кода. Над объявлением класса добавьте следующую строку:

Такая запись называется атрибутом, и это метаданные для кода, которые сообщают Unity, что класс можно сериализовать, и означают, что вы можете превратить объект в поток байтов и сохранить в файл на диске.

Примечание. Атрибуты имеют широкий спектр применения и позволяют прикреплять данные к классу, методу или переменной (эти данные известны как метаданные). Вы даже можете определить свои собственные атрибуты для использования в коде. Сериализация использует атрибуты [SerializeField] и [System.Serializable] , чтобы знать, что писать при сериализации объекта. Другие варианты использования атрибутов включают настройки для модульных тестов и внедрения зависимостей, которые выходят за рамки этого урока, но их стоит изучить.

Весь скрипт сохранения save должен выглядеть так:

Затем откройте скрипт Game и добавьте следующий метод:

Этот код создает экземпляр класса Save, который вы создали ранее, а затем устанавливает значения из существующих роботов. Он также сохраняет выстрелы и попадания игроков.

Кнопка Save подключена к методу SaveGame в скрипте Game, но кода в SaveGame пока нет. Замените функцию SaveGame следующим кодом:

Рассматриваем комментарий за комментарием:

  1. Создать экземпляр Save со всеми данными текущего сеанса, сохраненными в нем.
  2. Создать BinaryFormatter и FileStream, передав путь для сохраняемого экземпляра Save. Он сериализует данные (в байты), записывает их на диск и закрывает FileStream. Теперь на вашем компьютере будет файл с именем gamesave.save. Файл .save использовался только в качестве примера, и вы могли использовать любое расширение для имени сохранения файла.
  3. Это просто сбрасывает игру, так что после сохранения игроком все находится в состоянии по умолчанию.

Чтобы сохранить игру, нажмите Escape в любой момент во время игры и нажмите кнопку Save. Вы должны заметить, что все сбрасывается, и в выводе консоли отображается примечание о том, что игра была сохранена.

LoadGame в скрипте Game связана с кнопкой Load. Откройте скрипт игры и найдите функцию LoadGame . Замените его следующим:

Рассмотрим код детально:

Сохранение данных с помощью JSON

Внешние скобки представляют родительский объект, который является JSON. Если вы знакомы со структурой данных Dictionary , то JSON похож. Файл JSON представляет собой сопоставление пар ключей и значений. Итак, в приведенном выше примере есть 3 пары ключ-значение. В JSON ключи всегда являются строками, но значения могут быть объектами (т.е. дочерними объектами JSON), массивами, числами или строками. Значение, установленное для ключа «message» - «hi», значение ключа «age» - число 22, а значение ключа «items» представляет собой массив с двумя строками в нем.

Сам объект JSON представлен типом String. Передав эти данные в виде строки, любой язык может легко воссоздать объект JSON из строки в качестве аргумента конструктора. Очень удобно и очень просто.

У каждого языка есть свой способ создания объекта из этого формата. Начиная с Unity 5.3 существует собственный метод для создания объекта JSON из строки JSON. Вы создадите JSON-представление рекорда игрока, а затем распечатаете его на консоли. Но вы расширяете эту логику, отправляя JSON на сервер.

В скрипте Game есть метод с именем SaveAsJSON, который подключен к кнопке SaveAsJSON. Замените SaveAsJSON следующим кодом:

Это создает экземпляр Save, как и раньше. Затем он создает строку JSON, используя метод ToJSON в классе JsonUtility. Затем он выводит результат на консоль.

Вывод данных сохранения в консоль редактора Unity

Если вы хотите преобразовать этот JSON в экземпляр Save , вы должны просто использовать:

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

Куда двигаться дальше?

Вы можете скачать итоговые файлы проекта вверху страницы.

Теперь вы получили мощный инструмент для создания отличных игр, позволяющий игрокам сохранять и загружать свои игры с помощью магии сериализации. Вы также узнали, что такое JSON и как его можно использовать для сохранения в облаке. Вы также узнали, для чего используется PlayerPrefs (настройки!) И для чего он не используется (сохранение игры).

Совсем недавно мы опубликовали серию уроков (1 часть, 2 часть, 3 часть, 4 часть) по созданию простой игры, используя очень распространенный игровой движок — Unity. В этой статье мы покажем, как организовать систему управления сохраненными играми в Unity. Мы будем писать меню как в Final Fantasy, где игроку предоставляется возможность создать новое уникальное сохранение или же продолжить уже существующее. Итак, к концу урока вы научитесь:

  • сохранять игру и загружать уже имеющуюся, используя сериализацию;
  • использовать статические переменные для сохранения данных при изменении сцены.

Подготовка к сериализации

Мы будем ссылаться на этот сценарий из других скриптов, а потому сделаем класс статичным, добавив ключевое слово static между public и class . Также не забудем удалить два автоматически созданных метода, поскольку нам не потребуется крепить скрипт ни к какому игровому объекту.

Полученный сценарий должен выглядеть вот так:

Мы хотим добавить немного функциональных возможностей нашему скрипту, а потому давайте пропишем несколько директив:

Первая строка позволит нам использовать динамические списки. Вторая — даст нужный функционал операционной системы по сериализации данных. А последняя директива позволяет нам работать с потоками ввода и вывода. Иными словами, она используется для создания и чтения файлов.

1 октября – 30 ноября, Онлайн, Беcплатно

Отлично, теперь мы готовы к сериализации данных!

Создание класса, с возможностью сериализации

Игры, похожие на Final Fantasy (то есть многие RPG), предлагают игроку выбрать класс персонажа. Например, рыцарь, разбойник или маг. Создайте новый скрипт, назовите его Game и объявите в нем переменные:

Обратите внимание на строчку [System.Serializable] , которая говорит движку, что этот скрипт может быть сериализован. Круто, не так ли? Как говорит официальная документация, Unity умеет сериализовать следующие типы данных:

  • Все базовые типы ( int , string , float , bool и т.д.).
  • Некоторые встроенные типы ( Vector2 , Vector3 , Vector4 , Quaternion , Matrix4x4 , Color , Rect и LayerMask ).
  • Все классы, унаследованные от UnityEngine.Object ( GameObject , Component , MonoBehavior , Texture2D и AnimationClip ).
  • Перечисляемый тип ( Enums ).
  • Массивы и списки типов данных, перечисленных выше.

Первая переменная, объявленная в нашем классе, — current — является статической ссылкой на экземпляр игры. Когда мы будем сохранять или загружать какие-либо данные, нам потребуется обратиться к «текущей» игре. При использовании статических переменных сделать это особенно просто, без вызова лишних методов. Очень удобно!

Обратите внимание на класс Character . Его еще у нас нет — давайте создадим новый скрипт с таким названием:

Ничего странного не заметили? Да, мы действительно создали новый класс, внутри которого есть ровно одна строковая переменная. Мы, конечно же, могли использовать в скрипте Game переменные типа string вместо экземпляров класса Character . Но целью нашей статьи является не то, как сделать лучше, а рассказать, как можно решить нашу проблему.

Теперь, когда наши классы настроены, перейдем обратно к скрипту SaveLoad и добавим возможность сохранения игры.

Сохранение игры

Что происходит по нажатию на кнопку «Загрузить игру»? Правильно — показывается список уже сохраненных игры, которые мы можем восстановить. Так давайте создадим список игр и назовем его savedGames:

А теперь напишем статическую функцию сохранения игры:

Разберемся с тем, что же выполняет эта функция. Сначала мы добавляем в ранее созданный список текущую игру. Так как в скрипте Game мы использовали статическую переменную current, то мы можем достаточно просто обратиться к ней: Game.current . После этого нам следует сериализовать список, для чего и создается экземпляр класса BinaryFormatter .

Далее при помощи класса FileStream мы создаем новый файл под названием savedGames.gd в специальной директории, в которой и должны храниться все игровые данные. Для названия файла сохранений будем использовать savedGames , а расширением будет gd (от словосочетания game data).

Примечание автора В качестве расширения файла вы можете использовать все, что угодно. Так, например, в играх The Elder Scrolls используется .esm .

Далее вызывается метод Serialize экземпляра класса BinaryFormatter , который и сохраняет в файл сериализованные данные. И на этом все — файл закрывается. Наша игра сохранена!

Загрузка игры

А здесь все довольно просто. Так как при сохранении игры мы создали файл и записали в него сериализованный список, то сейчас нам придется открыть его и десериализовать имеющиеся в нем данные:

Алгоритм предельно прост. Для начала мы проверяем, существует ли файл сохранений. Если существует, то мы создаем новый экземпляр класса BinaryFormatter , открываем файл savedGames.gd и записываем в список savedGames десериализованные данные, считанные из файла.

Обратите внимание на 5 строчку. Метод Deserialize вернет нам битовую последовательность и, присвоив списку savedGames то, что возвращает функция Deserialize , мы ни к чему хорошему не придем. И поэтому нам следует полученную битовую последовательность преобразовать (привести) к типу List <Game> .

Примечание автора Тип данных, к которому вы приводите десериализованные данные, может быть совершенно разным. Например: Player.lives = (int)bf.Deserialize(file); .

Вывод

Итак, теперь вы знаете, как реализовать систему сохранения и загрузки игровых данных. Наш скрипт готов, и в окончательном виде он выглядит вот так:

Таковы основы работы с игровыми данными в Unity. В файле проекта вы можете найти несколько других скриптов, которые демонстрируют, как я применяю написанные нами функции и как я отображаю данные при помощи Unity GUI.

Большинство проектов созданных в Unity часто имеют систему хранения игровых данных. Эта система включает в себя инструменты для сохранения и загрузки данных. Как и где хранить эти данные часто зависит от того что это за игра, кто в нее играет и какое кол-во данных необходимо сохранить. Обычно различают два вида хранения данных: локальную, облачную (удаленную) и комбинированную.

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

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

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

В этой статье рассмотрим локальный тип хранения данных, и для этого в Unity есть очень простой инструмент PlayerPrefs.

Методы работы

Для начала рассмотрим способы записи данных в реестр с помощью PlayerPrefs.

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

  • SetInt. Метод используется для записи целого числа(integer) в реестр.
  • SetFloat. Метод для записи числа с “плавающей” запятой или дробного числа(float).
  • SetString. Метод для записи текстовых данных.

Для загрузки есть аналогичные методы, которые возвращают сохраненные ранее данные под определенным ключом.

  • GetInt. Метод используется для считывания целого числа(integer) из реестра.
  • GetFloat. Метод для считывания дробного числа(float).
  • GetString. Метод для считывания текстовых данных.

И так, мы разобрали основные методы для работы с PlayerPrefs, теперь попробуем сохранить с помощью этой системы некоторые данные в игре.

Игра представляет собой небольшую аркаду в которой необходимо отстреливать инопланетные корабли до того как они захватят главную базу.

Начнем с простого сохранения кол-ва уничтоженных кораблей.

Создадим небольшой скрипт Control унаследованный от MonoBehaviour.

  1. publicclass Control : MonoBehaviour
  2. publicint kills = 0 ;
  3. >

В числовой переменной kills будем хранить кол-во уничтоженных кораблей.

Теперь добавим метод сохранения Save.

  1. publicclass Control : MonoBehaviour
  2. publicint kills = 0 ;
  3. publicvoid Save () <>
  4. >

В игре этот метод вызывается через UI кнопку.


После нажатия этой кнопки переменная kills запишется в реестр под указанным ключом.

  1. publicclass Control : MonoBehaviour
  2. publicint kills = 0 ;
  3. publicvoid Save ()
  4. string key = “ MyGame” ;
  5. PlayerPrefs . SetInt ( key, this . kills );
  6. PlayerPrefs . Save ();
  7. >
  8. >

И так первым действие указываем в переменной key ключ под которым необходимо будет записать данные, пусть, к примеру название ключа будет MyGame, далее вызываем метод SetInt в который передаем ключ и переменную kills, в конце завершаем запись данных в реестре с помощью метода Save.

Проверить записи данных можно в реестре. Для быстрого входа в реестр необходимо нажать комбинацию кнопок Win + R, после чего в окошке “Выполнить” ввести regedit и нажать “Ok”.


Далее необходимо найти раздел с игрой. Все данные unity проектов хранятся в разделе HKEY_CURRENT_USER/Software/Unity/UnityEditor/DefaultCompany в этом разделе находим проектом по названию, там и будут храниться все записи программы.


В разделе “Параметр” можно увидеть название ключа под которым записаны данные, а в разделе “Значение” число равное кол-ву уничтоженных кораблей в игре.

Именно в этом разделе мы будем хранить все остальные данные из игры.

Загрузка данных

Теперь необходимо произвести чтение данных из реестра.

Загрузку будет проводить при старте игры, для этого заведем новый метод Start в скрипте Control.

В методе Load, в переменную key укажем ключ под которым записаны наши данные.

Теперь с помощью условия проверим: существуют ли наш ключ в реестре, для этого используем метод HasKey.

Если ключ существует значит можно загрузить данные из реестра.

Отлично, данные загрузились.

Комплексные данные

И так, теперь мы научились сохранять и загружать самые элементарные данные из реестра. Теперь попробуем проделать все тоже самое с кол-во очков в игре, для этого объявим новую дробную переменную scores.

  1. publicclass Control : MonoBehaviour
  2. publicint kills = 0 ;
  3. publicfloat scores = 0f ;
  4. >

Теперь немного расширим метод Save, чтобы сохранить эту новую переменную в реестр.

  1. publicclass Control : MonoBehaviour
  2. publicint kills = 0 ;
  3. publicfloat scores = 0f ;
  4. publicvoid Save ()
  5. string key = “ MyGame” ;
  6. PlayerPrefs . SetInt ( key, this . kills );
  7. PlayerPrefs . SetFloat ( key, scores );
  8. PlayerPrefs . Save ();
  9. >
  10. >

В методе Load проведем аналогичные действия только по загрузке переменной scores.

Запускаем игру, чтобы проверить работоспособность системы.

Текстовые данные


Кол-во жизней базы это тоже дробное число float, а так как ячейка дробного числа уже занята переменной scores, то получается, что мы не сможем поместить еще одну. В этом случае на помощь приходят текстовые данные. Мы просто преобразуем все данные для сохранения в текст и запишем его в реестр в текстовую ячейку, которая все еще пустая. Для удобного преобразования множества данных в текст и обратно используем JSONUtility.

И так объявим новую переменную health в скрипте Control где будем хранить кол-во жизней базы.

  1. publicclass Control : MonoBehaviour
  2. publicint kills = 0 ;
  3. publicfloat scores = 0f ;
  4. publicfloat health = 100 ;
  5. >

Теперь нам нужен объект который будет хранить все эти три переменные. Для этого подойдет простой класс SaveData. Создадим новый скрипт SaveData и уберем у него наследование от MonoBehaviour.

Переходим в метод Save, откуда сотрем последние два действия SetInt и SetFloat.

  1. publicclass Control : MonoBehaviour
  2. publicint kills = 0 ;
  3. publicfloat scores = 0f ;
  4. publicfloat health = 100 ;
  5. publicvoid Save ()
  6. string key = “ MyGame” ;
  7. SaveData data = new SaveData ();
  8. PlayerPrefs . Save ();
  9. >
  10. >

Сначала создаем новый экземпляр класса SaveData, после чего наполняем его данными.

  1. publicclass Control : MonoBehaviour
  2. publicint kills = 0 ;
  3. publicfloat scores = 0f ;
  4. publicfloat health = 100 ;
  5. publicvoid Save ()
  6. string key = “ MyGame” ;
  7. SaveData data = new SaveData ();
  8. data . kills = this . kills ;
  9. data . scores = this . scores ;
  10. data . health = this . health ;
  11. PlayerPrefs . Save ();
  12. >
  13. >

Теперь необходимо преобразовать объект data в текст, для чего воспользуемся методом ToJson класса JsonUtility.

  1. publicclass Control : MonoBehaviour
  2. publicint kills = 0 ;
  3. publicfloat scores = 0f ;
  4. publicfloat health = 100 ;
  5. publicvoid Save ()
  6. string key = “ MyGame” ;
  7. SaveData data = new SaveData ();
  8. data . kills = this . kills ;
  9. data . scores = this . scores ;
  10. data . health = this . health ;
  11. stringvalue = JsonUtility . ToJson ( data );
  12. PlayerPrefs . Save ();
  13. >
  14. >

После чего сохраняем полученный текст в реестр с помощью метода SetString.

  1. publicclass Control : MonoBehaviour
  2. publicint kills = 0 ;
  3. publicfloat scores = 0f ;
  4. publicfloat health = 100 ;
  5. publicvoid Save ()
  6. string key = “ MyGame” ;
  7. SaveData data = new SaveData ();
  8. data . kills = this . kills ;
  9. data . scores = this . scores ;
  10. data . health = this . health ;
  11. stringvalue = JsonUtility . ToJson ( data );
  12. PlayerPrefs . SetString ( key, value );
  13. PlayerPrefs . Save ();
  14. >
  15. >

Теперь необходимо проделать действия по загрузке данных в методе Load и перевести текст обратно в объект SaveData с помощью того же JSONUtility.

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

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

Запускаем для проверки.

Сохранение и загрузка работают исправно. Переходим в реестр и проверяем данные.


Теперь в разделе “Значение” мы видим текст со всеми переменными и их значениями.

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


В этом уроке вы узнаете, как сохранять и загружать игру в Unity, используя PlayerPrefs, Serialization и JSON.

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

В этом уроке вы узнаете:

  • Что такое сериализация и десериализация.
  • Что такое PlayerPrefs и как его использовать для сохранения настроек игрока.
  • Как создать файл сохранения игры и сохранить его на диск.
  • Как загрузить файл сохраненной игры.
  • Что такое JSON и как вы можете его использовать.

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

Введение

Загрузите стартовый проект здесь. Вы будете использовать специальный код для сохранения и загрузки игры, а также изучите логику сохранения настроек игроков.

Важные концепции сохранения

Существует четыре ключевых понятия которыми можно охарактеризовать процесс сохранения в Unity:

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


Десериализация: Это процесс, противоположный сериализации, а именно преобразование потока байтов в объект.

Player Prefs

Откройте проект, который вы скачали, запустите сцену с именем Game и затем нажмите play.


Чтобы начать игру, нажмите кнопку «New Game». В этой игре вам необходимо использовать мышку для перемещения. Нажмите левую кнопку мыши, чтобы выстрелить и поразить цели (которые перемещаются вверх и вниз через различные промежутки времени), получать очки за каждое удачное попадание. Попробуйте и посмотрите, сколько очков вы сможете получить за 30 секунд. Чтобы вызвать меню в любое время, нажмите клавишу escape.


Эта игра довольна забавная и даже увлекательная, но без музыкального сопровождения немного скучновата. Возможно, вы заметили, что есть музыкальный переключатель, но он был выключен. Нажмите «Play», чтобы начать новую игру, но на этот раз нажмите «Music» и установите значение «On», чтобы вы могли услышать музыку, когда начнете игру. Убедитесь, что ваши колонки или наушники подключены!


Для начала создайте новый скрипт с именем PlayerSettings в папке Scripts. Поскольку вы будете использовать некоторые элементы пользовательского интерфейса, добавьте следующую строку вверху:

Именно они будут отслеживать объекты Toggle и AudioSource.

Далее добавьте следующую функцию:

Эти настройки означают:

  1. Осуществляется проверка, есть ли в PlayerPrefs кэшированная настройка для кнопки «music». Если там нет никакого значения, то создается несколько ключ-значений для кнопки звука со значением 1. Кроме того, тут происходит включение и выключение переключателя AudioSource. Эти настройки будут использованы при первом запуске игры. Значение 1 используется, потому что вы не можете сохранить какое-то определенное логическое значение (но вы можете использовать 0 как false и 1 как true).
  2. Тут идет проверка ключа «music», сохраненного в PlayerPrefs. Если значение установлено на 1, значит на проигрывателе была включена музыка, поэтому активируется режим воспроизведения звуков и соответствующий переключатель. В противоположном случае музыку наоборот выключается, а тумблер переходит в отметку OFF.

Теперь сохраните изменения в вашем скрипте и вернитесь в Unity.

Добавьте скрипт PlayerSettings в GameObject и разверните пользовательский интерфейс GameObject. Далее вам нужно открыть меню GameObject, чтобы увидеть его дочерние элементы. Перетащите объект Music GameObject в поле Toggle сценария PlayerSettings, выберите GameObject Game и перетащите AudioSource в поле MyAudio.


Музыка настроена на работу во время игры (так как в функции «Awake» есть код), но вам все равно нужно добавить еще один код, если игрок меняет настройки во время игры. Для этого снова откройте скрипт PlayerSettings и добавьте следующую функцию:

Эти настройки означают почти то же самое, что и код, который вы написали ранее, за исключением того, что в этом случае есть одно важное отличие. Этот код сначала проверяет состояние переключателя музыки, а затем соответствующим образом обновляет сохраненную настройку. Для того, чтобы этот метод был вызван и, следовательно, чтобы он мог выполнять свою функцию, вам нужно установить метод обратного вызова в Toggle GameObject. Выберите MusicObject Music и перетащите GameObject Game поверх поля объекта в разделе OnValueChanged:


Теперь к раскрывающемуся списку, в котором в данный момент написано «No Function», и выберите PlayerSettings ⇒ ToggleMusic (). Таким образом, когда во время игры пользователь активирует кнопку переключения в меню, появится функция ToggleMusic.


Теперь у вас есть все необходимые настройки, которые нужны чтобы отслеживать опции звуков. Нажмите «Play» и попробуйте изменить настройки музыки, включив или выключив соответствующий переключатель в меню.


Сохранение игры

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

Первым шагом к созданию файла сохранения игры является создание класса файла сохранения. Создайте новый скрипт с именем Save и удалите пункты MonoBehaviour, Start () и Update ().

Теперь вам необходимо добавить следующие переменные:

Чтобы сохранить игру, вам нужно отслеживать, где находятся существующие роботы и какого они типа. За это должны отвечать два списка с целыми данными о количестве попаданий и числе выстрелов.

Есть еще один очень важный фрагмент кода, который вам также нужно добавить:

Этот код дает команду Unity, что данный класс можно сериализовать, а это означает, что вы можете превратить его в поток байтов и сохранить как файл на диске.

Примечание: все эти атрибуты имеют широкий спектр применения и позволяют привязывать данные к классу, методу или определенной переменной. Вы даже можете определить свои собственные атрибуты для использования в вашем коде. Сериализация использует атрибуты [SerializeField] и [System.Serializable], которые определяют, что происходит при сериализации объекта.

Ваш скрипт Save должен выглядеть следующим образом:

Теперь откройте скрипт Game и добавьте еще один метод:

Этот код создаст новый экземпляр класса Save, который вы делали ранее, а затем установит значения исходя из количества существующих роботов. Кроме того, произойдет сохранение количества выстрелов игрока и попаданий.

Кнопка «Save» была подключена к методу SaveGame в скрипте Game, но в SaveGame все еще нет кода. Замените функцию SaveGame следующим кодом:

Рассмотрим все по пунктам:

  1. Создается экземпляр Save со всеми данными текущего сеанса, сохраненными в нем.
  2. Создается BinaryFormatter и FileStream, передав путь для сохранения экземпляру Save. Тут же происходит процесс сериализации данных в байты, с последующим их сохранением на диск и закрытием FileStream. Теперь на вашем компьютере будет файл с именем save. Вы можете использовать любое расширение для имени файла сохранения.
  3. Идет сброс настроек игры в состояние по умолчанию.


LoadGame в скрипте Game подключен к кнопке Load. Откройте скрипт Game, найдите функцию LoadGame и замените ее следующим значением:

Рассмотрим процесс более подробно:


Сохранение данных с помощью JSON

Сам объект JSON представлен типом String. Передав эти данные в виде строки, любой язык может легко воссоздать объект JSON из строки в качестве аргумента конструктора. Это действительно очень удобно и очень просто. У каждого языка есть свой способ создания объекта из этого формата. Начиная с Unity 5.3, существует собственный метод для создания объекта JSON из строки JSON.

В скрипте Game есть метод SaveAsJSON, который подключен к кнопке Save As JSON. Вам нужно заменить следующим кодом:

Это создает экземпляр Save и строку JSON с использованием метода ToJSON в классе JsonUtility.

Запустите игру и попробуйте уничтожить несколько целей, чтобы набрать очки. Теперь нажмите Escape, чтобы вызвать меню и используйте кнопку Save As JSON, чтобы увидеть созданную вами строку JSON:


Если вы захотите преобразовать этот JSON в экземпляр Save, то вам нужно будет использовать строку:

Таким образом вы сможете загрузить файл сохранения из Интернета, а затем добавить его в свою игру.

Что делать дальше?

Вы можете скачать законченный проект тут.

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

Если вы хотите узнать больше о возможностях Unity, то вам следует обратиться к другим урокам, посвященным этому движку. Если вы уверенно владеете Unity и хотите стать настоящим разработчиком, то советуем вам прочитать книгу Unity Games by Tutorials, с помощью которой вы сможете сделать 4 полноценных игры с нуля.

Читайте также: