如何在引用Scriptable Object的脚本检视器中查看并编辑其字段?
可行,实现方法如下
在Unity里完全可以做到不用选中ScriptableObject资源,直接在引用它的脚本检视器中编辑其字段,下面是两种常用的实现方式:
方法一:自定义PropertyDrawer(全局通用)
这种方式可以让所有标记了特定属性的ScriptableObject引用,都能在检视器中直接展开编辑内部字段,适用性广。
步骤1:定义自定义属性和ScriptableObject类
using UnityEngine; // 标记需要内联编辑的ScriptableObject的属性 public class InlineScriptableObjectAttribute : PropertyAttribute { } // 你的ScriptableObject示例类 [CreateAssetMenu(fileName = "NewData", menuName = "Custom/Data")] public class MyScriptableObject : ScriptableObject { public int myInt; public float myFloat; public string myString; }
步骤2:编写PropertyDrawer实现内联绘制
using UnityEditor; using UnityEngine; [CustomPropertyDrawer(typeof(InlineScriptableObjectAttribute))] public class InlineScriptableObjectDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // 先绘制默认的ScriptableObject引用选择框 EditorGUI.PropertyField(position, property, label); // 如果已有引用,展开绘制内部字段 if (property.objectReferenceValue != null) { EditorGUI.indentLevel++; var serializedObj = new SerializedObject(property.objectReferenceValue); serializedObj.Update(); // 遍历所有可序列化字段(跳过默认的m_Script字段) var iterator = serializedObj.GetIterator(); if (iterator.NextVisible(true)) { do { position.y += EditorGUI.GetPropertyHeight(iterator); EditorGUI.PropertyField(EditorGUI.IndentedRect(position), iterator); } while (iterator.NextVisible(false)); } serializedObj.ApplyModifiedProperties(); EditorGUI.indentLevel--; } } // 计算整个属性需要的高度(包含引用框和内部字段) public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { float height = EditorGUI.GetPropertyHeight(property, label); if (property.objectReferenceValue != null) { var serializedObj = new SerializedObject(property.objectReferenceValue); var iterator = serializedObj.GetIterator(); if (iterator.NextVisible(true)) { do { height += EditorGUI.GetPropertyHeight(iterator); } while (iterator.NextVisible(false)); } } return height; } }
步骤3:在脚本中使用
在引用ScriptableObject的MonoBehaviour里,给字段加上自定义属性即可:
using UnityEngine; public class TestScript : MonoBehaviour { [InlineScriptableObject] public MyScriptableObject data; }
方法二:自定义Editor(针对特定脚本)
如果只需要在某个特定的MonoBehaviour中实现内联编辑,直接写自定义Editor会更灵活,能精准控制要显示的字段。
using UnityEditor; using UnityEngine; [CustomEditor(typeof(TestScript))] public class TestScriptEditor : Editor { public override void OnInspectorGUI() { var targetScript = (TestScript)target; // 绘制ScriptableObject引用选择框 targetScript.data = (MyScriptableObject)EditorGUILayout.ObjectField("数据对象", targetScript.data, typeof(MyScriptableObject), false); // 引用不为空时,绘制内部字段 if (targetScript.data != null) { EditorGUILayout.Space(); EditorGUILayout.LabelField("内部字段", EditorStyles.boldLabel); EditorGUI.indentLevel++; targetScript.data.myInt = EditorGUILayout.IntField("整数", targetScript.data.myInt); targetScript.data.myFloat = EditorGUILayout.FloatField("浮点数", targetScript.data.myFloat); targetScript.data.myString = EditorGUILayout.TextField("字符串", targetScript.data.myString); EditorGUI.indentLevel--; // 标记资源已修改,确保修改能保存 if (GUI.changed) { EditorUtility.SetDirty(targetScript.data); } } } }
注意事项
- 两种方式修改的都是ScriptableObject资源本身,所有引用该资源的脚本都会同步看到修改;
- 使用SerializedObject的
ApplyModifiedProperties或EditorUtility.SetDirty确保修改能保存到资源文件; - 可根据需求扩展PropertyDrawer的逻辑,比如添加折叠按钮、处理嵌套的可序列化对象等。
内容的提问来源于stack exchange,提问作者Fahim kamal Ahmed
相关产品推荐
相关产品推荐

