Обновление (23 апреля 2019 г.)

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

В исторических целях и для людей, использующих старые версии, я оставлю этот пост.

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

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

Последнее обновление этой статьи - Unity 5.6.

Типы постоянных данных

При написании пользовательских инструментов вы можете хранить примерно два типа данных:

  • Настройки - данные, относящиеся к конкретным пользователям и полезные только для одного человека. Обычно это что-то необязательное, например цветовые темы или шрифты.

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

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

Дополнительные примеры вы можете найти в самом редакторе Unity. Вы найдете значения, которые хранятся в качестве предпочтений в окне «Unity / Preferences», а общие данные (настройки) в «Edit / Project Settings».

Сохранение настроек редактора

Для настройки редактора вам следует использовать класс Unity с удобным названием EditorPrefs. EditorPrefs позволяет пользователям быстро сохранять пары ключ-значение на диске пользователя. В Windows они сохраняются в реестре, а на Mac они сохраняются в папке библиотеки пользователя как файлы списка свойств (plist). Вы можете просматривать и редактировать эти значения в Windows с помощью RegEdit или XCode на Mac.

Поскольку эти значения хранятся на диске и вне проекта, они не будут проверяться в системе управления версиями и, следовательно, не будут использоваться пользователями.

Использование EditorPrefs API довольно просто. Для каждого значения вы указываете EditorPrefs с ключом для сохранения значения. Тип значения указывается в зависимости от вызываемой функции. Вот пример:

var isDarkSkin = EditorPrefs.GetBool(“ColorSchemes_Skin”);

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

При их использовании рекомендуется использовать префикс, уникальный для вашего настраиваемого инструмента, чтобы другие разработчики случайно не нарушили ваши ценности. Например, вместо того, чтобы выбирать просто «Кожа» в приведенном выше примере, я поставил перед ней префикс «ColorSchemes_». Таким образом, другой объект, использующий скин, не перезапишет мои значения.

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

Сохранение настроек проекта

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

PlayerPrefs обычно предназначены для хранения настроек во время выполнения (в игре), таких как полноэкранный режим и разрешение, но они также работают для сохранения настроек в редакторе.

Так же, как с EditorPrefs, вы можете отлаживать и просматривать свои настройки с помощью XCode или RegEdit, или вы можете использовать пользовательский актив, такой как Advanced Player Prefs, чтобы редактировать их изнутри Unity.

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

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

//Ex: “DoodadPainter/RedBlueGames.Sparklite/CurrentBrush”
var projectPrefix = PlayerSettings.companyName + “.” + PlayerSettings.productName;

Я использую название компании и название продукта в сочетании, чтобы отразить то, как Unity хранит PlayerPrefs.

Сохранение общих данных

Общие данные - это наиболее сложный тип данных для сохранения, и Unity не дает никаких указаний или рекомендаций о том, как это сделать. Чтобы обмениваться данными между пользователями, нам необходимо решить, как хранить данные и где их хранить. По сути, существует бесконечное количество способов сделать это, но я решил, что лучше всего сохранить данные как ScriptableObject внутри папки Resources в проекте (по адресу « Assets / Resources / ”, если быть точным).

ScriptableObjects для хранения данных

Сохранение данных в виде файла в проекте позволяет нам легко регистрировать их в системе управления версиями и делиться ими между пользователями. Это также позволяет нам копировать файл из проекта в проект, если мы хотим поделиться данными или настройками между проектами. Вы, конечно, можете использовать базовый File.IO для создания текстового файла (JSON), но Unity имеет более стандартизированный и оптимизированный способ обработки сериализации данных: ScriptableObjects.

ScriptableObjects - это, по сути, контейнеры данных, которые могут быть сохранены как активы в проекте. Они могут хранить любые типы данных, которые могут быть сериализованы Unity (примитивы, такие как string, int и bool, а также общие Списки). С ними также могут быть связаны скрипты и логика, что делает их очень мощными инструментами. Каждый программист, использующий Unity, должен хорошо разбираться в ScriptableObjects, поэтому, если вы не знакомы с ними, вам, вероятно, следует прекратить читать это и пойти и узнать о них.

Где хранить актив ScriptableObject

Теперь, когда мы решили сохранить наши данные в ScriptableObject, нам нужно выяснить, где их хранить. Первая мысль, которая может возникнуть у вас, - просто сохранить файл данных в любом месте, где хранится ваш пользовательский ресурс, по жестко заданному пути (например, «Assets / SuperGameCreator / SGCData.asset»). Это будет работать в большинстве случаев, если только пользователь не решит переместить ваш актив в другую папку, например в папку «ThirdPartyAssets», что пользователи обычно захотят сделать. Затем, когда вы загружаете данные по жестко заданному пути, их там не будет, и вам придется воссоздать их.

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

Для решения этих проблем мы можем использовать папку Ресурсы.

Папка Ресурсы - это особая папка, в которой вы можете хранить ресурсы для динамической загрузки. Чаще всего он используется для загрузки ресурсов во время выполнения в игре, но вы также можете использовать его для загрузки ресурсов в редакторе. Вы получаете доступ к ресурсам по имени, используя `Resources.Load (string filename-no-extension)`. Причина, по которой эта папка так удобна для общих данных и настроек, заключается в том, что содержимое всех папок Resources включается при использовании `Resources.Load`. Поэтому, если у вас есть ресурс в папке Resources, который не является непосредственным дочерним элементом Assets, например Assets / CustomTools / MyTool / Resources / FileB.asset, вы сможете загрузить его через Resources.Load (ФайлB). Этот простой факт позволяет пользователям перемещать его в любом месте своего проекта (при условии, что они перемещают вместе с ним папку Ресурсы). Поскольку это стандартная папка, вполне вероятно, что у пользователей уже есть ресурсы, которые они хранят в своей папке ресурсов. Некоторые инструменты, такие как замечательная библиотека анимации DoTween от Demigiant, позволяют пользователям изменять место сохранения общих данных в зависимости от пользовательских предпочтений.

Также обратите внимание, что вы должны поместить настройки, которые используются только в редакторе, в подпапку редактора (Editor / Resources / File.asset), чтобы они не были упакованы в сборку (благодаря Noise Преступление за указание на это и Владислав Глинский за исправление этого пути).

Единственным серьезным недостатком использования папки «Ресурсы» является то, что она по существу разделяет расположение вашего инструмента на два места, и я подозреваю, что некоторые пользователи воспримут это как беспорядок в своем проекте. Но я думаю, что если бы больше инструментов использовали это соглашение для хранения, это было бы незначительными недостатками. Тем не менее, если какие-либо разработчики Unity читают это, было бы неплохо получить общий каталог и API для этого типа вещей.

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

Заключение

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

  • Нужно ли другим пользователям получать мои изменения в этих данных? (Общие данные)
  • Захотят ли другие проекты импортировать эти данные? (Общие данные)
  • Следует ли помнить об этом, когда я открываю другой проект? (Настройки редактора)
  • Следует ли помнить об этом, когда я повторно открываю этот проект (Настройки редактора / Настройки проекта)

С EditorPrefs и ScriptableObjects вы можете хранить все, что вам нужно, чтобы максимально повысить удобство использования ваших инструментов.

В качестве примера того, как на практике работать с настройками редактора и общими данными, я создал образец проекта Custom Tool on GitHub. Это также хороший пример сценариев редактора в целом, поэтому вы можете свободно просматривать его и использовать любой код, который может вам понадобиться.

Спасибо за прочтение! Вы можете связаться со мной в Твиттере, чтобы задать вопросы или комментарии о статье, программировании игры или о чем-то еще. Вы также можете следить за нашим журналом разработчиков, чтобы узнавать о прогрессе в нашей игре, Sparklite, Unity, пиксельной графике, программировании и многом другом.