版本: Unity 6 (6000.0)
语言英语
  • C#

SerializedObject

UnityEditor 中的类

建议更改

成功!

感谢您帮助我们提高 Unity 文档的质量。虽然我们无法接受所有提交内容,但我们会阅读用户提出的每个建议更改,并在适用的情况下进行更新。

关闭

提交失败

由于某些原因,您的建议更改无法提交。请<a>稍后再试</a>。感谢您抽出时间帮助我们提高 Unity 文档的质量。

关闭

取消

描述

SerializedObject 和 SerializedProperty 是用于以完全通用的方式编辑 Unity 对象 上序列化字段的类。这些类会自动处理单个序列化字段的修改,以便它们会被 撤消 系统处理,并在 Inspector 中绘制时针对预制体覆盖进行正确样式化。

在许多情况下,您可以创建工具来修改项目中的对象。例如,以下脚本示例创建了一个菜单项,该菜单项重置当前选定的所有游戏对象的本地位置。将其放在名为 Editor 文件夹中的 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 点以这种方式编辑对象,但您还必须使用其他编辑器 API 来指定哪些组件已被修改,以便此操作可撤消,并且在下次保存场景时会被检测为更改,依此类推。相反,使用 SerializedObject 会自动处理此过程。以下脚本示例与上一个示例具有相同的效果,但也可撤消,并且在场景中被跟踪为更改。将其放在名为 Editor 文件夹中的 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 对象 的数据流,这使您可以同时编辑对象共享的序列化数据。例如,如果您在数据流中有多个不同类型的 行为,它们可能唯一的共同属性就是“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 定义了一个自定义 编辑器,它在默认控件之后添加了一个按钮以随机化正弦函数参数。将其放在名为 Editor 文件夹中的 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(); } } }

编辑器 类有一个 serializedObject 属性,该属性提供了一个流到所有被检查的目标(在本例中为 SineAnimation 组件),这使得轻松支持同时编辑多个对象成为可能。因为此 SerializedObject 实例会持续存在于 编辑器 实例的生命周期中,所以 OnInspectorGUI 的基本实现会在绘制任何控件之前处理调用 Update,以及在任何用户交互之后调用 ApplyModifiedProperties。因此,在按下添加到此检查器的按钮时所做的修改都必须在方法退出之前通过 ApplyModifiedProperties 刷新,否则它们将在 Editor.OnInspectorGUI 的基本实现下次调用 SerializedObject.Update 方法时丢失。

请注意,通过 SerializedObject.ApplyModifiedProperties 将数据刷新到 Unity 对象不会尊重您可能在与序列化字段关联的属性设置器中具有的任何数据验证逻辑。在此示例中,'m_PhaseShift' 字段的值在 phaseShift 属性设置器和 UI(通过 RangeAttribute)中都限制在 0 到 1 之间。因为用户可以通过 SerializedProperty(以及通过编辑磁盘上的资产)访问 'm_PhaseShift',而不仅仅是通过 'phaseShift' API 或 UI 访问,所以有必要在 MonoBehaviour.OnValidate 回调中也将其限制在有效范围内,这将在加载 Unity 对象 时对数据进行清理。

另请注意,尽管 SerializedObject 旨在与多个目标一起使用,但 SerializedProperty 类上的值获取器属性(例如,floatValuevector3Value)不是多选友好的。因此,为它们赋值会影响所有目标,但从它们读取值只会返回列表中第一个目标关联的值。

其他资源:SerializedPropertySerializeFieldEditorMonoBehaviour.OnValidatehasMultipleDifferentValues

属性

context用于存储和解析 ExposedReference 类型的上下文。这由 SerializedObject 构造函数设置。
forceChildVisibility控制子隐藏字段的可见性。
hasModifiedProperties当 SerializedObject 具有尚未应用的已修改属性时为 true。
isEditingMultipleObjects序列化对象是否由于多对象编辑而表示多个对象?(只读)
maxArraySizeForMultiEditing定义超出该大小后,在选择多个对象时无法编辑数组的大小。
targetObject被检查的对象(只读)。
targetObjects被检查的对象(只读)。

构造函数

SerializedObject为被检查的对象创建 SerializedObject。

公共方法

ApplyModifiedProperties应用属性修改。
ApplyModifiedPropertiesWithoutUndo应用属性修改,但不注册撤消操作。
CopyFromSerializedProperty将值从 SerializedProperty 复制到序列化对象上的相应序列化属性。
CopyFromSerializedPropertyIfDifferent将已更改的值从 SerializedProperty 复制到序列化对象上的相应序列化属性。
FindProperty按名称查找序列化属性。
GetIterator获取第一个序列化属性。
SetIsDifferentCacheDirty在下一个 /Update()/ 调用时更新 hasMultipleDifferentValues 缓存。
Update更新序列化对象的表示。
UpdateIfRequiredOrScript更新序列化对象的表示,仅当对象自上次调用 Update 以来已被修改或它是脚本时。