SerializedObject
класс в UnityEditor
Описание
SerializedObject и SerializedProperty являются классами для редактирования серийных полей на объектах Unity в полностью общий способ. Эти классы автоматически обрабатывают загрязнение индивидуальных серийных полей, так что они будут обрабатываться системой Undo и стилизованы правильно для переопределений Префаб при рисовании в Inspector.
Во многих случаях вы можете создавать инструменты для модификации объектов в вашем проекте. Например, следующий пример скрипта создает пункт меню, который сбросает локальную позицию всех выбранных в данный момент GameObjects. Поместите его в файл Example1.cs в папке Редактор:
using UnityEditor; using UnityEngine;
static class Example1 { [MenuItem("Edit/Reset Selected Objects Position (No Undo)")] static void ResetPosition() { // this action will not be undoable foreach (var go in Selection.gameObjects) go.transform.localPosition = Vector3.zero; } }
Хотя вы можете редактировать объекты через их точки API таким образом, вам также придется использовать другой редактор APIs, чтобы указать, какие компоненты были загрязнены, так что это действие будет отменено и будет обнаружено как изменение при следующем сохранении Scene и так далее. В отличие от этого, использование SerializedObject обрабатывает этот процесс автоматически. Следующий пример скрипта имеет тот же эффект, что и предыдущий, но также отменяется и отслеживается как изменение в Scene. Поместите его в файл с названием Example2.cs в папку с названием Редактор:
using System.Linq; using UnityEditor; using UnityEngine;
static class Example2 { [MenuItem("Edit/Reset Selected Objects Position")] static void ResetPosition() { var transforms = Selection.gameObjects.Select(go => go.transform).ToArray(); var so = new SerializedObject(transforms); // you can Shift+Right Click on property names in the Inspector to see their paths so.FindProperty("m_LocalPosition").vector3Value = Vector3.zero; so.ApplyModifiedProperties(); } }
SerializedObject открывает поток данных для одного или нескольких целевых Unity объектов одновременно, что позволяет одновременно редактировать серийные данные, которые объекты имеют в общем. Например, если у вас есть несколько Behaviours объектов разных типов в потоке данных, единственное свойство, которое у них общее, может быть'm_Enabled'.
При первом создании экземпляра SerializedObject он обновляется. Любые изменения, которые вы делаете в SerializedProperty, доступные в этом потоке данных, должны в конечном итоге быть сброшены методом SerializedObject.ApplyModifiedProperties. Если вы сохраняете ссылку на экземпляр SerializedObject более чем на один кадр, вы должны вручную вызвать его метод SerializedObject.Update перед чтением любых данных из него, так как один или несколько целевых объектов могут быть изменены в другом месте, например, из отдельного потока SerializedObject. Соответственно, обратите внимание, что два различных потока SerializedObject с одинаковыми целевыми объектами независимы друг от друга и вы должны вручную синхронизировать их таким образом, если один или несколько из них поддерживаются в течение нескольких кадров.
Одним из наиболее распространенных применений классов SerializedObject и SerializedProperty является создание пользовательских классов Editors, где использование SerializedObject является рекомендованным подходом, в отличие от изменения объектов непосредственно.
В следующем примере скрипт определяет компонент, который анимирует локальное положение объекта с помощью синусоидальной функции. Поместите его в скрипт под названием SineAnimation.cs:
using UnityEngine;
public class SineAnimation : MonoBehaviour { public Vector3 axis { get { return m_Axis; } set { m_Axis = value; } } [SerializeField] private Vector3 m_Axis = Vector3.up;
public float period { get { return m_Period; } set { m_Period = value; } } [SerializeField] private float m_Period = 1f / Mathf.PI;
public float amplitude { get { return m_Amplitude; } set { m_Amplitude = value; } } [SerializeField] private float m_Amplitude = 1f;
public float phaseShift { get { return m_PhaseShift; } set { m_PhaseShift = Mathf.Clamp01(value); } } [SerializeField, Range(0f, 1f)] private float m_PhaseShift;
void Update() { transform.localPosition = m_Axis * m_Amplitude * Mathf.Sin((Time.time + m_PhaseShift) / m_Period); }
void OnValidate() { m_PhaseShift = Mathf.Clamp01(m_PhaseShift); } }
В следующем примере скрипт определяет пользовательский Editor для SineAnimation, который добавляет кнопку после стандартных элементов управления для случайного изменения параметров синусовой функции. Поместите его в файл SineAnimationEditor.cs в папку Редактор:
using UnityEditor; using UnityEngine;
[CustomEditor(typeof(SineAnimation)), CanEditMultipleObjects] public class SineAnimationEditor : Editor { public override void OnInspectorGUI() { base.OnInspectorGUI(); if (GUILayout.Button("Randomize Sine Function", EditorStyles.miniButton)) { serializedObject.FindProperty("m_Period").floatValue = Random.Range(0f, 10f); serializedObject.FindProperty("m_Amplitude").floatValue = Random.Range(0f, 10f); serializedObject.FindProperty("m_PhaseShift").floatValue = Random.Range(0f, 1f); serializedObject.ApplyModifiedProperties(); } } }
Editor класс имеет Editor.serializedObject свойство, которое обеспечивает поток для всех инспектируемых целей (SineAnimation компонентов в этом случае), что облегчает поддержку редактирования нескольких объектов одновременно. Потому что этот экземпляр SerializedObject сохраняется в течение всего срока жизни объекта Editor например, базовая реализация OnInspectorGUI обрабатывает вызов Update перед рисованием любых элементов управления, а также вызов ApplyModifiedProperties после любого взаимодействия с пользователем. Таким образом, изменения, сделанные при нажатии кнопки, добавленной к этому инспектору, должны быть сброшены через ApplyModifiedProperties перед выходом метода, или они будут потеряны при следующей базовой реализации метода. Editor.OnInspectorGUI вызывает SerializedObject.Update метод на Editor.serializedObject экземпляр.
Обратите внимание, что сброс данных в объект Unity через SerializedObject.ApplyModifiedProperties не будет учитывать никакую логику проверки данных, которая может быть установлена в параметрах свойств, связанных с серийными полями. В этом примере значение поля 'm_PhaseShift' закреплено между 0 и 1, как в параметре свойства phaseShift, так и в UI (через RangeAttribute). Потому что пользователи могут получить доступ к 'm_PhaseShift' через SerializedProperty (а также путем редактирования ассета на диске) и не только через 'phaseShift' API или UI, необходимо также зажимать его к действительному диапазону в MonoBehaviour.OnValidate callback, который будет очищать данные, когда Unity объект загружен.
Учтите также, что хотя SerializedObject рассчитан на работу с несколькими целями, свойства-получатели значений класса SerializedProperty (например, SerializedProperty.floatValue, SerializedProperty.vector3ValueТаким образом, назначение им значения повлияет на все цели, но чтение значения из них возвращает только значение, связанное с первой целью в списке.
Дополнительные ресурсы: SerializedProperty, SerializeField, Editor, MonoBehaviour.OnValidate, SerializedProperty.hasMultipleDifferentValues.
Свойства
| Свойство | Описание |
|---|---|
| context | Контекст, используемый для хранения и разрешения типов ExposedReference. Он устанавливается конструктором SerializedObject. |
| forceChildVisibility | Управляет видимостью скрытых полей дочерних объектов. |
| hasModifiedProperties | Истинно, когда SerializedObject имеет измененное свойство, которое не было применено. |
| isEditingMultipleObjects | Представляет ли серийный объект несколько объектов из-за многообъектного редактирования? (только для чтения) |
| maxArraySizeForMultiEditing | Определяет максимальный размер, после которого массивы нельзя редактировать при выборе нескольких объектов. |
| targetObject | Проверяемый объект (только для чтения). |
| targetObjects | Инспектируемые объекты (только для чтения). |
Конструкторы
| Конструктор | Описание |
|---|---|
| SerializedObject | Создать SerializedObject для проверяемого объекта. |
Открытые методы
| Метод | Описание |
|---|---|
| ApplyModifiedProperties | Применение изменений свойств. |
| ApplyModifiedPropertiesWithoutUndo | Применяет изменения свойств без регистрации операции отмены. |
| CopyFromSerializedProperty | Копирует значение из SerializedProperty в соответствующее serialized свойство на serialized объекте. |
| CopyFromSerializedPropertyIfDifferent | Копирует измененное значение из SerializedProperty в соответствующее serialized свойство на serialized объекте. |
| FindProperty | Найти сериализованное свойство по имени. |
| GetIterator | Получить первое серийное свойство. |
| SetIsDifferentCacheDirty | Обновить кэш hasMultipleDifferentValues при следующем вызове /Update()/. |
| Update | Обновить представление сериализованного объекта. |
| UpdateIfRequiredOrScript | Обновить представление серийизованного объекта, только если объект был изменён после последнего вызова Update или если это скрипт. |