You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在PropertyDrawer中不使用Begin/EndProperty或PropertyField更新序列化类值?

问题描述

正在将某类的CustomEditor部分功能转换为PropertyDrawer,希望该类始终使用同一编辑器,但此前因转换复杂度较高而搁置。存在一些同时用于运行时和编辑器的函数,希望避免在PropertyDrawer UI中重复实现。

获取对象引用的代码:

var myObject = (MyClass)fieldInfo.GetValue(property.serializedObject.targetObject);

尝试修改的代码示例:

// Size Property
//
EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(position, sizeProperty);
if (EditorGUI.EndChangeCheck())
{
    var newX = xProperty.intValue;
    var newY = yProperty.intValue;

    myObject.SetSize(newX, newY); // <- "myObject" is the object being drawn by the PropertyDrawer
}

遇到的问题:即使直接修改对象引用,序列化数据也未更新,似乎Unity会从SerializedProperty重建序列化数据。被调用的函数会操作底层对象的字段(这些字段未使用PropertyField或BeginProperty/EndProperty),希望找到无需重写编辑器UI逻辑的解决办法。


解决方案

核心问题在于Unity的SerializedObject/SerializedProperty是对象序列化数据的缓存副本:直接修改对象实例的字段不会自动同步到缓存,反之缓存的修改也不会自动覆盖对象。要让自定义函数的修改被序列化系统认可,需要手动同步两者的状态。

方法一:同步修改后的对象状态到SerializedProperty

调用共用函数修改对象后,将处理后的字段值同步回对应的SerializedProperty,再提交修改:

EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(position, sizeProperty);
if (EditorGUI.EndChangeCheck())
{
    var newX = xProperty.intValue;
    var newY = yProperty.intValue;

    // 记录对象状态,支持Unity编辑器撤销操作
    Undo.RecordObject(myObject, "Adjust Size");
    // 调用共用函数处理值,修改对象底层字段
    myObject.SetSize(newX, newY);

    // 将处理后的字段值同步回SerializedProperty缓存
    xProperty.intValue = myObject.x;
    yProperty.intValue = myObject.y;

    // 提交修改,让序列化系统保存最新值
    property.serializedObject.ApplyModifiedProperties();
    // 标记对象为脏数据,确保修改被写入磁盘(针对MonoBehaviour/ScriptableObject)
    EditorUtility.SetDirty(myObject);
}

方法二:强制从对象刷新SerializedProperty缓存

如果不想手动同步每个字段,可以调用serializedObject.Update()让缓存直接从对象读取最新状态:

EditorGUI.BeginChangeCheck();
EditorGUI.PropertyField(position, sizeProperty);
if (EditorGUI.EndChangeCheck())
{
    var newX = xProperty.intValue;
    var newY = yProperty.intValue;

    Undo.RecordObject(myObject, "Adjust Size");
    myObject.SetSize(newX, newY);

    // 强制从对象读取最新数据,更新SerializedProperty缓存
    property.serializedObject.Update();
}

关键注意事项

  1. Undo.RecordObject:必须在修改对象前调用,否则编辑器无法记录撤销操作,影响用户体验。
  2. 字段可序列化性:确保MyClass中被SetSize修改的字段(如x、y)是Unity可序列化的(即public或标记[SerializeField]),否则SerializedProperty无法访问这些字段。
  3. 自定义可序列化类:如果MyClass是嵌套的可序列化类(非MonoBehaviour/ScriptableObject),无需调用EditorUtility.SetDirty,只需确保其所属的父对象被正确标记即可。

内容的提问来源于stack exchange,提问作者hijinxbassist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 19:23:12