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

如何为Unity脚本字段添加「覆盖默认值」复选框?

问题

我遇到了相同的问题:修改脚本里的默认字段值后,场景、预制体中的对象不会同步更新,仍保留旧值。例如:

public class SomeScript : MonoBehaviour
{
    public float someParameter = 30; // 原为10
                                     // 修改此处的值后,场景、预制体等对象不会同步更新
                                     // 它们仍保留值10
...
}

这是因为Unity会自动序列化字段值,所以预制体中的旧值不会随脚本默认值变化而更新。

试过逐个给预制体点击「重置」,或是临时添加[NonSerialized]属性(修改字段名也可)再保存移除,这些操作都十分繁琐。

注意到「Visual Effect Graph」编辑器解决了该问题:每个属性旁配有复选框,取消勾选时,预制体将始终采用脚本里的最新默认值;需要时也可手动覆盖默认值。
Visual Effect Graph

问询
  1. 如何为所有脚本的字段/属性添加这种「覆盖默认值」复选框?
  2. 是否有替代方案:让特定属性可在编辑器(或游戏模式)中编辑,但不被Unity序列化?
    希望找到无需大量重复工作的方案,比如不用为每个脚本编写自定义Editor(这种方式效率太低)。
解决方案

一、实现类似VEG的「覆盖默认值」复选框(无需逐个编写Editor)

可以利用Unity的Property Drawer和自定义属性,一次性为所有字段添加该功能:

  1. 创建自定义属性类
using UnityEngine;

public class UseDefaultAttribute : PropertyAttribute { }
  1. 编写对应的Property Drawer,在编辑器中绘制复选框与字段
using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(UseDefaultAttribute))]
public class UseDefaultDrawer : PropertyDrawer
{
    private bool useDefault = false;

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        // 划分复选框与字段的绘制区域
        Rect checkboxRect = new Rect(position.x, position.y, 20, position.height);
        Rect propertyRect = new Rect(position.x + 25, position.y, position.width - 25, position.height);

        // 绘制复选框
        useDefault = EditorGUI.Toggle(checkboxRect, useDefault);

        if (useDefault)
        {
            // 使用默认值时,禁用字段编辑,显示脚本默认值
            GUI.enabled = false;
            object defaultValue = GetDefaultValue(property);
            EditorGUI.LabelField(propertyRect, label.text, defaultValue.ToString());
            GUI.enabled = true;

            // 同步序列化值为默认值,确保运行时一致
            if (property.floatValue != (float)defaultValue)
            {
                property.floatValue = (float)defaultValue;
                property.serializedObject.ApplyModifiedProperties();
            }
        }
        else
        {
            // 不使用默认值时,正常绘制可编辑字段
            EditorGUI.PropertyField(propertyRect, property, label);
        }
    }

    // 通过反射获取脚本字段的默认值
    private object GetDefaultValue(SerializedProperty property)
    {
        System.Type targetType = property.serializedObject.targetObject.GetType();
        System.Reflection.FieldInfo fieldInfo = targetType.GetField(property.name);
        return fieldInfo?.GetValue(null);
    }
}
  1. 使用方式
    在需要该功能的字段上添加[UseDefault]属性即可:
public class SomeScript : MonoBehaviour
{
    [UseDefault]
    public float someParameter = 30;
}

添加属性后,字段旁会出现复选框,取消勾选时自动同步脚本默认值,勾选时可自定义字段值。

二、替代方案:可编辑但不序列化的字段

如果只需要字段在编辑器中可编辑,但不被Unity序列化(即脚本默认值修改后自动生效),可选用以下两种方法:

方法1:[NonSerialized]+自定义Drawer显示字段

[NonSerialized]标记的字段不会被Unity序列化,但默认不会在Inspector面板显示,可通过自定义Drawer让它显示并允许编辑:

using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(NonSerializedAttribute))]
public class NonSerializedDrawer : PropertyDrawer
{
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        EditorGUI.PropertyField(position, property, label);
    }
}

使用时直接给字段加[NonSerialized]即可:

[NonSerialized]
public float someParameter = 30;

注意:这类字段在进入Play模式或保存场景时会重置为脚本默认值,适合无需保存自定义值的场景。

方法2:用OnValidate()同步默认值

无需修改编辑器代码,在脚本中添加OnValidate()方法实现默认值同步:

public class SomeScript : MonoBehaviour
{
    private const float DefaultSomeParameter = 30;
    public float someParameter = DefaultSomeParameter;

    private void OnValidate()
    {
        // 若要强制所有实例使用默认值,取消下方注释
        // someParameter = DefaultSomeParameter;
    }
}

该方法实现简单,但灵活性不如Property Drawer方案。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:54:28