【问题标题】:unity conditional fields custom editorunity 条件字段自定义编辑器
【发布时间】:2019-09-02 14:51:54
【问题描述】:

我的目标: 我有一个脚本

public class MyScript: MonoBehaviour
{
   public bool A;
   public bool B;
}

只有当 A 为真时,我才需要 B 可见

我已经对脚本进行了扩展,并在标题中添加了 UnityEditor

[CustomEditor(typeof(MyScript))]
public class MyEditor : Editor
{
    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        MyScript tool = (MyScript) target;

        tool.A = GUILayout.Toggle(tool.A, "Flag");

        if(tool.A)
        {
            tool.B= EditorGUILayout.Toggle(tool.B, "Flag");
        }
    }
}

但并没有真正改变。 我做错了什么?

【问题讨论】:

    标签: unity3d unity3d-editor unity-editor


    【解决方案1】:

    首先你的类定义是错误的。您要么需要[Serializable],要么该类应从MonoBehaviour 继承,如果它应附加到游戏对象。无论哪种方式删除()

    [Serializable]
    public class MyScript
    {
       public bool A;
       public bool B;
    }
    

    public class MyScript : MonoBehaviour
    {
       public bool A;
       public bool B;
    }
    

    然后请注意,Custom Editor适用于继承自 MonoBehaviourScriptableObject 的类。在其他情况下,您将不得不实现Custom PropertyDrawer

    您应该始终尝试直接在target 中进行更改。您必须自己处理很多事情,例如标记为脏、撤消/重做等...

    而总是通过SerializedPropertys。

    还要注意base.OnInspectorGUI(); 将绘制默认检查器


    所以假设 MyScript 是一个 MonoBehaviour

    [CustomEditor(typeof(MyScript))]
    public class MyEditor : Editor
    {
        SerializedProperty a;
        SerializedProperty b;
    
        // is called once when according object gains focus in the hierachy
        private void OnEnable()
        {
            // link serialized properties to the target's fields
            // more efficient doing this only once
            a = serializedObject.FindProperty("A");
            b = serializedObject.FindProperty("B");
        }
    
        public override void OnInspectorGUI()
        {
            // fetch current values from the real instance into the serialized "clone"
            serializedObject.Update();
    
            // Draw field for A
            EditorGUILayout.PropertyField(a);
    
            if(a.boolValue)
            {
                // Draw field for B
                EditorGUILayout.PropertyField(b);
            }
    
            // write back serialized values to the real instance
            // automatically handles all marking dirty and undo/redo
            serializedObject.ApplyModifiedProperties();
        }
    }
    

    或者如果MyScript实际上不是MonoBehaviour,那么PropertyDrawer的工作原理基本上非常相似,除了你必须使用总是需要位置Rect作为参数的字段的EditorGUI版本:

    [CustomPropertyDrawer(typeof(MyScript), true)]
    public class MyEditor : PropertyDrawer
    {
        private bool isUnFolded;
    
        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            // draw folder for the entire class
            isUnFolded = EditorGUI.Foldout(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), isUnFolded, label);
            // go to the next line
            position.y += EditorGUIUtility.singleLineHeight;
    
            // only draw the rest if unfolded
            if (isUnFolded)
            {
                // draw fields indented
                EditorGUI.indentLevel++;
    
                // similar to before get the according serialized properties for the fields
                var a = property.FindPropertyRelative("A");
                var b = property.FindPropertyRelative("B");
    
                // Draw A field
                EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), a);
                position.y += EditorGUIUtility.singleLineHeight;
    
                if (a.boolValue)
                {
                    // Draw B field
                    EditorGUI.PropertyField(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), b);
                }
    
                // reset indentation
                EditorGUI.indentLevel--;
            }
        }
    
        // IMPORTANT you have to implement this since your new property is
        // higher then 1 single line
        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            // default is 1 single line
            var height = 1;
            // if unfolded at least 1 line more, if a is true 2 lines more
            if(isUnFolded) height += (property.FindPropertyRelative("A").boolValue ? 2 : 1);
    
            return height * EditorGUIUtility.singleLineHeight;
        }
    }
    

    【讨论】:

    • 有些错误是好的。我应该首先将它写为 MonoBehaviour(更新了问题),因为这就是我的课程(错别字),但是您不会将答案扩展到 PropertyDrawer。所以我现在感谢你两次。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多