在Unity中修改Inspector面板布尔值时如何触发属性Set方法
问题原因
- Unity 序列化系统仅对字段做序列化处理,你在 Inspector 面板看到的复选框对应的是标记了
[SerializeField]的私有字段aBool,而非自定义的ABool属性。直接修改 Inspector 中的值是直接修改底层字段,不会触发属性的set逻辑,属于 Unity 正常行为,你的属性定义本身没有语法错误,只是没有和 Inspector 修改行为做绑定。 - 另外你当前的属性
set逻辑是先判断旧字段值与新值的差异再更新字段,如果你直接将修改后的字段值传入属性,会因为字段已经是最新值,导致差异判断无法触发。
解决方法
方法1:配合缓存旧值使用OnValidate回调(全版本通用,无需自定义编辑器)
OnValidate是 Unity 内置生命周期方法,Inspector 中的序列化字段被修改时会自动触发,我们额外缓存一个旧值做差异判断即可触发正确的set逻辑:
public class SomeClass : MonoBehaviour { [SerializeField] private bool aBool; // 缓存字段旧值 private bool _oldABool; public bool ABool { get { return aBool; } set { // 值无变化直接退出 if (aBool == value) return; Debug.Log("we are setting the bool!"); // 从false改为true时触发 if (aBool == false && value == true) { // do stuff } // 从true改为false时触发 if (aBool == true && value == false) { // do stuff } aBool = value; // 更新缓存旧值 _oldABool = value; } } private void Awake() { // 初始化缓存旧值 _oldABool = aBool; } private void OnValidate() { // 可选:仅运行模式下触发逻辑可以加这句判断 // if (!Application.isPlaying) return; // 字段值与缓存旧值不同,说明是Inspector修改触发 if (aBool != _oldABool) { // 先把字段还原为旧值,再赋值给属性触发正确的差异判断 var newValue = aBool; aBool = _oldABool; ABool = newValue; } } // 其余业务代码省略 }
方法2:自定义Inspector(逻辑最直观,无版本限制)
将私有序列化字段标记为[HideInInspector]隐藏Inspector显示,再通过自定义编辑器直接操作ABool属性,修改时自动触发set逻辑:
首先是主类代码:
public class SomeClass : MonoBehaviour { // 隐藏原字段的Inspector显示 [HideInInspector] [SerializeField] private bool aBool; public bool ABool { get { return aBool; } set { if (aBool == value) return; Debug.Log("we are setting the bool!"); if (aBool == false && value == true) { // do stuff } if (aBool == true && value == false) { // do stuff } aBool = value; } } // 其余业务代码省略 }
然后在Editor文件夹下新建编辑器脚本:
using UnityEditor; using UnityEngine; [CustomEditor(typeof(SomeClass))] public class SomeClassEditor : Editor { public override void OnInspectorGUI() { base.OnInspectorGUI(); var someClass = (SomeClass)target; // 绘制ABool属性的复选框 bool newABool = EditorGUILayout.Toggle("ABool", someClass.ABool); if (newABool != someClass.ABool) { // 记录撤销操作 Undo.RecordObject(someClass, "Change ABool"); // 直接赋值给属性触发set逻辑 someClass.ABool = newABool; // 标记对象为已修改 EditorUtility.SetDirty(someClass); } } }
这种写法逻辑最直观,不需要额外缓存旧值,不管是代码赋值还是Inspector修改都会触发set逻辑。
内容的提问来源于stack exchange,提问作者MoreFoam
相关产品推荐
相关产品推荐

