Описание
SerializedObject и SerializedProperty — это классы для редактирования сериализованных полей в объектах Unity совершенно общим способом. Эти классы автоматически обрабатывают загрязнение отдельных сериализованных полей, поэтому они будут обработаны системой Undo и правильно оформлены для переопределений Prefab при рисовании в Инспекторе.
Во многих случаях вы можете создавать инструменты для изменения объектов в вашем проекте. Например, в следующем примере скрипта создается пункт меню, который сбрасывает локальную позицию всех выбранных в данный момент игровых объектов. Поместите его в файл с именем Example1.cs в папке с именем Editor:
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-точки, вам также придется использовать другие API-интерфейсы редактора, чтобы указать, какие компоненты были изменены, чтобы это действие нельзя было выполнить и оно было обнаружено как изменение в следующий раз, когда Сцена сохраняется и так далее. Напротив, использование SerializedObject обрабатывает этот процесс автоматически. Следующий пример сценария имеет тот же эффект, что и предыдущий, но его также нельзя отменить, и он отслеживается как изменение сцены. Поместите его в файл с именем Example2.cs в папке с именем Editor:
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 является создание пользовательских редакторов, где использование 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);
}
}
В следующем примере сценария определяется пользовательский редактор для SineAnimation, который добавляет кнопку после элементов управления по умолчанию для рандомизации параметров синусоидальной функции. Поместите его в файл с именем SineAnimationEditor.cs в папке с именем Editor:
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 имеет свойство serializedObject, которое обеспечивает поток для всех проверяемых целей (компоненты SineAnimation в в данном случае), что позволяет легко поддерживать одновременное редактирование нескольких объектов. Поскольку этот экземпляр SerializedObject сохраняется в течение всего времени существования экземпляра Editor, базовая реализация OnInspectorGUI обрабатывает вызов Update перед рисованием любых элементов управления, а также вызов ApplyModifiedProperties после любого взаимодействия с пользователем. Таким образом, все изменения, сделанные при нажатии кнопки, добавленной в этот инспектор, должны быть сброшены с помощью ApplyModifiedProperties перед выходом из метода, иначе они будут потеряны при следующей базовой реализации Editor.OnInspectorGUI вызывает метод SerializedObject.Update для экземпляра serializedObject.
Обратите внимание, что передача данных в объект Unity через SerializedObject.ApplyModifiedProperties не будет учитывать логику проверки данных, которая может быть у вас в установщиках свойств, связанных с сериализованными полями. В этом примере значение поля «m_PhaseShift» фиксируется между 0 и 1 как в установщике свойства PhaseShift, так и в пользовательском интерфейсе (через RangeAttribute). Поскольку пользователи могут получить доступ к 'm_PhaseShift' через SerializedProperty (а также путем редактирования ресурса на диске), а не только через API 'phaseShift' или пользовательский интерфейс, необходимо также зафиксируйте его в допустимом диапазоне в обратном вызове MonoBehaviour.OnValidate, который будет очищать данные при загрузке объекта Unity. .
Также обратите внимание, что хотя SerializedObject предназначен для работы с несколькими целевыми объектами, свойства получателя значений в классе SerializedProperty (например, floatValue, vector3Value) не поддерживает множественный выбор. Таким образом, присвоение им значения повлияет на все цели, но чтение значения из них возвращает только значение, связанное с первой целью в списке.
Смотрите так же: SerializedProperty, SerializeField, Editor, MonoBehaviour.OnValidate, hasMultipleDifferentValues.
Свойства
context | Контекст, используемый для хранения и разрешения типов ExposedReference. Это задается конструктором SerializedObject. |
hasModifiedProperties | Истинно, если SerializedObject имеет измененное свойство, которое не было применено. |
isEditingMultipleObjects | Представляет ли сериализованный объект несколько объектов из-за редактирования нескольких объектов? (Только чтение) |
maxArraySizeForMultiEditing | Определяет максимальный размер, после которого нельзя редактировать массивы при выборе нескольких объектов. |
targetObject | Просматриваемый объект (только для чтения). |
targetObjects | Проверяемые объекты (только для чтения). |
Конструкторы
SerializedObject | Создаёт SerializedObject для проверяемого объекта. |
Публичные Методы
ApplyModifiedProperties | Применить изменения свойств. |
ApplyModifiedPropertiesWithoutUndoотмены | Применяет изменения свойств без регистрации операции отмены. |
CopyFromSerializedProperty | Копирует значение из SerializedProperty в соответствующее сериализованное свойство сериализованного объекта. |
CopyFromSerializedPropertyIfDifferent | Копирует измененное значение из SerializedProperty в соответствующее сериализованное свойство сериализованного объекта. |
FindProperty | Поиск сериализованного свойства по имени. |
GetIterator | Получить первое сериализованное свойство. |
SetIsDifferentCacheDirty | Обновить кэш hasMultipleDifferentValues при следующем вызове /Update()/. |
Update | Обновить представление сериализованного объекта. |
UpdateIfRequiredOrScript | Обновить представление сериализованного объекта, только если объект был изменен с момента последнего вызова Update или если это скрипт. |