Unity中ScriptableObject变量的OnValueChanged触发方法可行性问询
绝对可以实现!我平时做Unity项目的时候,经常用到几种不同的方式来实现这个需求,根据场景选就行,给你挨个捋一遍:
方法1:用Unity内置的
OnValidate()方法 这是最简单直接的方案,Unity会在编辑模式下Inspector里修改值时自动调用,同时在脚本被加载、重置的时候也会触发,完美适配ScriptableObject的使用场景。
举个实际代码例子:
using UnityEngine; [CreateAssetMenu(fileName = "MyData", menuName = "Custom/My Data")] public class MyScriptableObject : ScriptableObject { [SerializeField] private int _myValue; // 当Inspector里的值被修改时自动触发 private void OnValidate() { // 调用你的自定义逻辑 OnValueChanged(); } private void OnValueChanged() { Debug.Log($"MyValue changed to: {_myValue}"); // 这里写你需要执行的操作,比如更新关联数据、触发事件、校验值的合法性等 } }
⚠️ 注意点:
OnValidate()是在编辑模式下运行的,如果你的逻辑里有运行时专属代码(比如Instantiate),记得用if (Application.isPlaying)做判断,避免编辑器报错。- 不管是值类型(int、float)还是引用类型(比如另一个ScriptableObject),修改时都会触发这个方法。
方法2:属性包装+
OnValidate()同步 如果想把逻辑封装在属性的setter里(比如做值的范围限制),可以用私有序列化字段配合公开属性,再通过OnValidate()同步逻辑:
using UnityEngine; [CreateAssetMenu(fileName = "MyData", menuName = "Custom/My Data")] public class MyScriptableObject : ScriptableObject { [SerializeField] private int _myValue; public int MyValue { get => _myValue; set { // 先做值的校验,比如限制在0-100之间 var clampedValue = Mathf.Clamp(value, 0, 100); if (_myValue != clampedValue) { _myValue = clampedValue; OnValueChanged(); } } } private void OnValidate() { // 确保Inspector修改字段后,属性的校验逻辑也能触发 MyValue = _myValue; } private void OnValueChanged() { Debug.Log($"MyValue updated to: {_myValue}"); } }
这样不管是代码里修改MyValue属性,还是Inspector里改_myValue字段,都会触发你的自定义逻辑。
方法3:自定义编辑器(精细控制场景)
如果需要更精细的控制(比如只监听某个特定字段的变化、做编辑器专属的UI交互),可以写一个自定义Editor类:
using UnityEditor; using UnityEngine; [CustomEditor(typeof(MyScriptableObject))] public class MyScriptableObjectEditor : Editor { private SerializedProperty _myValueProp; private int _previousValue; private void OnEnable() { // 获取序列化的目标字段 _myValueProp = serializedObject.FindProperty("_myValue"); // 记录初始值用于后续对比 _previousValue = _myValueProp.intValue; } public override void OnInspectorGUI() { // 更新序列化对象的状态 serializedObject.Update(); // 绘制默认的Inspector字段 EditorGUILayout.PropertyField(_myValueProp); // 检查值是否发生变化 if (_myValueProp.intValue != _previousValue) { // 调用目标ScriptableObject的自定义方法 ((MyScriptableObject)target).OnValueChanged(); // 更新记录的旧值 _previousValue = _myValueProp.intValue; } // 应用所有修改 serializedObject.ApplyModifiedProperties(); } }
这种方式适合需要监听特定字段、或者在值变化时刷新编辑器预览窗口等场景。
额外小提醒
如果需要在值变化时通知场景中的MonoBehaviour对象,可以在OnValueChanged()里用UnityEvent或者自定义事件系统,但要注意编辑模式下的事件触发——接收方可能需要加[ExecuteInEditMode]标记,或者用EditorApplication.update来监听变化。
内容的提问来源于stack exchange,提问作者Tung Le Minh
相关产品推荐
相关产品推荐

