如何为Unity脚本字段添加「覆盖默认值」复选框?
问题
我遇到了相同的问题:修改脚本里的默认字段值后,场景、预制体中的对象不会同步更新,仍保留旧值。例如:
public class SomeScript : MonoBehaviour { public float someParameter = 30; // 原为10 // 修改此处的值后,场景、预制体等对象不会同步更新 // 它们仍保留值10 ... }
这是因为Unity会自动序列化字段值,所以预制体中的旧值不会随脚本默认值变化而更新。
试过逐个给预制体点击「重置」,或是临时添加[NonSerialized]属性(修改字段名也可)再保存移除,这些操作都十分繁琐。
注意到「Visual Effect Graph」编辑器解决了该问题:每个属性旁配有复选框,取消勾选时,预制体将始终采用脚本里的最新默认值;需要时也可手动覆盖默认值。
问询
- 如何为所有脚本的字段/属性添加这种「覆盖默认值」复选框?
- 是否有替代方案:让特定属性可在编辑器(或游戏模式)中编辑,但不被Unity序列化?
希望找到无需大量重复工作的方案,比如不用为每个脚本编写自定义Editor(这种方式效率太低)。
解决方案
一、实现类似VEG的「覆盖默认值」复选框(无需逐个编写Editor)
可以利用Unity的Property Drawer和自定义属性,一次性为所有字段添加该功能:
- 创建自定义属性类
using UnityEngine; public class UseDefaultAttribute : PropertyAttribute { }
- 编写对应的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); } }
- 使用方式
在需要该功能的字段上添加[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
相关产品推荐
相关产品推荐

