Для чего используются SerializedObject, SerializedProperty, AssetDatabase?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
SerializedObject, SerializedProperty и AssetDatabase: ключевые инструменты редактора Unity
В Unity-разработке, особенно при создании кастомных инспекторов, редакторских окон и инструментов, SerializedObject, SerializedProperty и AssetDatabase образуют триаду фундаментальных классов, обеспечивающих работу с данными внутри редактора Unity. Их основное назначение — предоставить безопасный, унифицированный и функциональный способ чтения, модификации и сохранения сериализованных данных объектов и ассетов, полностью интегрированный с системой Undo/Redo и автоматическим обновлением инспектора.
SerializedObject: контейнер для управления сериализованными данными
SerializedObject — это представление одного или нескольких объектов Unity (наследников UnityEngine.Object) в виде их сериализованных данных. Он выступает в роли посредника между C#-скриптом (например, кастомным редактором) и фактическими полями объекта в памяти.
- Основная цель: Обеспечить безопасное изменение свойств объектов в редакторе с поддержкой операций Undo (отмена) и автоматическим уведомлением об изменениях.
- Ключевые сценарии использования:
* Создание кастомных инспекторов (`Editor`-классов) для компонентов или ScriptableObject.
* Редактирование нескольких выделенных объектов одновременно.
* Обход сложной иерархии данных объекта (массивы, вложенные классы).
- Типичный workflow:
1. Создать `SerializedObject` из целевого объекта.
2. Получить `SerializedProperty` для нужного поля.
3. Использовать методы `SerializedObject.Update()` и `ApplyModifiedProperties()` для синхронизации.
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(MyComponent))]
public class MyComponentEditor : Editor
{
private SerializedProperty _healthProperty;
private SerializedProperty _nameProperty;
void OnEnable()
{
// Создаем SerializedObject на основе целевого объекта (автоматически предоставляется базовым Editor)
// serializedObject уже создан базовым классом Editor
// Находим сериализованные свойства по имени поля в скрипте
_healthProperty = serializedObject.FindProperty("health");
_nameProperty = serializedObject.FindProperty("unitName");
}
public override void OnInspectorGUI()
{
// Обновляем сериализованное представление, чтобы отразить текущие значения объекта
serializedObject.Update();
// Редактируем свойства с помощью встроенных методов EditorGUI
EditorGUILayout.PropertyField(_nameProperty);
EditorGUILayout.IntSlider(_healthProperty, 0, 100);
// Применяем изменения ко всем объектам, на которые ссылается SerializedObject,
// регистрируем операцию для Undo и отмечаем объекты как "грязные"
if (serializedObject.ApplyModifiedProperties())
{
Debug.Log("Значения изменены и сохранены!");
}
}
}
SerializedProperty: "указатель" на конкретное поле
SerializedProperty — это представление отдельного сериализованного поля (property) внутри SerializedObject. Это может быть примитив (int, float, string), ссылка на UnityEngine.Object, массив (SerializedProperty.isArray == true) или поле вложенного класса.
- Основная цель: Предоставить унифицированный API для доступа и модификации значения поля, его атрибутов (например,
[Range]) и мета-информации, независимо от его типа. - Ключевые особенности:
* **Обход иерархии:** Позволяет "гулять" по свойствам-детям (`SerializedProperty.Copy()`, `.GetArrayElementAtIndex()`, `.FindPropertyRelative()`).
* **Безопасность:** Изменения через `SerializedProperty` автоматически интегрируются с системой `SerializedObject`.
* **Универсальность:** Использует методы `.intValue`, `.floatValue`, `.objectReferenceValue`, `.stringValue`, `.vector3Value` и т.д., в зависимости от типа свойства (`propertyType`).
- Пример работы с массивом:
SerializedProperty itemsArray = serializedObject.FindProperty("items");
EditorGUILayout.LabelField("Элементы:", EditorStyles.boldLabel);
for (int i = 0; i < itemsArray.arraySize; i++)
{
SerializedProperty element = itemsArray.GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(element, new GUIContent($"Элемент {i}"));
}
AssetDatabase: менеджер файловой системы проекта Unity
AssetDatabase — это статический класс, который предоставляет API для работы с ассетами (файлами) внутри папки Assets проекта. Он абстрагирует низкоуровневые файловые операции, обеспечивая их корректность с точки зрения Unity (обновление мета-файлов, импорт, ре-импорт, кеширование).
- Основная цель: Управление жизненijным циклом ассетов в редакторе: создание, загрузка, сохранение, переименование, перемещение, поиск.
- Ключевые функции:
* **Создание ассетов:** `AssetDatabase.CreateAsset()`, `AssetDatabase.GenerateUniqueAssetPath()`.
* **Загрузка и поиск:** `AssetDatabase.LoadAssetAtPath()`, `AssetDatabase.FindAssets()`.
* **Модификация файлов:** `AssetDatabase.Refresh()` (критически важный метод после скриптовой работы с файлами), `AssetDatabase.SaveAssets()`, `AssetDatabase.ImportAsset()`.
* **Работа с метаданными:** `AssetDatabase.GetDependencies()`, `AssetDatabase.CopyAsset()`, `AssetDatabase.MoveAsset()`.
- Пример создания ScriptableObject через редакторный скрипт:
using UnityEditor;
using UnityEngine;
public class AssetCreator
{
[MenuItem("Tools/Create MyConfig")]
static void CreateConfigAsset()
{
// Создаем экземпляр ScriptableObject в памяти
MyScriptableObject config = ScriptableObject.CreateInstance<MyScriptableObject>();
config.someValue = 42;
// Генерируем уникальный путь для сохранения
string path = EditorUtility.SaveFilePanelInProject(
"Сохранить конфиг",
"NewConfig",
"asset",
"Выберите место для сохранения"
);
if (!string.IsNullOrEmpty(path))
{
// Создаем ассет на диске и сохраняем файл
AssetDatabase.CreateAsset(config, path);
AssetDatabase.SaveAssets(); // Фиксируем изменения в БД ассетов
AssetDatabase.Refresh(); // Обновляем окно Project
EditorUtility.FocusProjectWindow();
Selection.activeObject = config; // Выделяем созданный ассет
}
}
}
Синергия и итог
Эти три инструмента часто используются вместе:
- AssetDatabase используется для поиска, загрузки или создания ассета (например,
ScriptableObject). - Для модификации полей этого загруженного ассета в редакторском коде создается SerializedObject.
- Через SerializedObject получаются конкретные SerializedProperty для редактирования.
- После применения изменений (
ApplyModifiedProperties()) может потребоваться вызовAssetDatabase.SaveAssets()для гарантированного сохранения ассета на диск.
Таким образом, SerializedObject и SerializedProperty — это инструменты для безопасного редактирования данных в памяти с полной поддержкой редакторского конвейера Unity, а AssetDatabase — это инструмент для управления файлами этих данных на диске в рамках проекта. Их правильное использование — признак профессионального подхода к созданию редакторских расширений в Unity.