如何在编辑器中的 ScriptableObject 中自定义列表/数组中类的外观?

问题描述 投票:0回答:1

我有一个 ScriptableObject,它只有一个对象列表:

    class MyClassHolder : ScriptableObject
    {
        public MyClass[] myClass;
    }
    [System.Serializable]
    public class MyClass
    {
        public string key;
        public int priority;

        public Data data;
    }

还有一些数据类:

    [System.Serializable]
    public class Data
    {
        public Icon icon;
        public Color color;
    }

    [System.Serializable]
    public class Icon
    {
        public TextureSet[] small;
        public TextureSet[] big;
    }

    [System.Serializable]
    public class TextureSet
    {
        public Texture2D texture;
        public Vector2 offset;
        [Range(0f, 1.2f)]
        public float scale = 1;
    }

现在看起来像这样:

enter image description here

我有绘制图标的代码,就像:

enter image description here

我想尝试做的是在“小”和“大”旁边添加一个预览,如果可以的话,像这样:

或者在这样的数据下:

enter image description here

我知道有 CustomEditor 或一些抽屉,但不知道哪个适合这种情况。

我应该和哪个班级一起工作?

更新: 我最终得到了这个,看起来不错 enter image description here

c# unity3d unity-editor unity3d-editor unity3d-gui
1个回答
1
投票

对于这个用例,我不会使用 CustomEditor,它用于为整个

ScriptableObject
MonoBehaviour
实现自定义检查器。仅自定义某个字段的绘制方式将带来大量开销。此外,您必须为使用此字段类型的每个其他类执行此操作。

您宁愿想要一个自定义

PropertyDrawer
,它用于实现自定义方式来仅绘制特定类型的字段 - 在您的情况下为
TextureSet
.

可能看起来有点像例如

...
#if UNITY_EDITOR
using UnityEditor;
#endif

[Serializable]
public class TextureSet
{
    public Texture2D texture;
    public Vector2 offset;
    [UnityEngine.Range(0f, 1.2f)]
    public float scale = 1;

#if UNITY_EDITOR
    [CustomPropertyDrawer(typeof(TextureSet))]
    private class TextureSetDrawer : PropertyDrawer
    {
        // height and width of the preview field in lines
        const float PREVIEW_SIZE_LINES = 4;

        // height and width of the preview field in pixels
        readonly float PREVIEW_SIZE = EditorGUIUtility.singleLineHeight * PREVIEW_SIZE_LINES;

        public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
        {
            if (!property.isExpanded)
            {
                // if folded simply single line
                return EditorGUIUtility.singleLineHeight;
            }

            // compose the total height of the poperty
            // 1 line - offset
            // 1 line - scale
            // PREVIEW_SIZE_LINES - preview
            // 1 line - a bit of buffer to separate from next list element
            return EditorGUIUtility.singleLineHeight * (2 + PREVIEW_SIZE_LINES + 1);
        }

        public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            using (new EditorGUI.PropertyScope(position, label, property))
            {
                if (!property.isExpanded)
                {
                    // draw the foldout label of the entire TextureSet property
                    property.isExpanded = EditorGUI.Foldout(position, property.isExpanded, label);
                }
                else
                {
                    // move down half buffer to separate a bit from previous fields
                    position.y += EditorGUIUtility.singleLineHeight * 0.5f;

                    // draw the foldout label of the entire TextureSet property
                    property.isExpanded = EditorGUI.Foldout(new Rect(position.x, position.y, position.width, EditorGUIUtility.singleLineHeight), property.isExpanded, label);
                    
                    // indent the child properties a bit for better visual grouping
                    using (new EditorGUI.IndentLevelScope())
                    {
                        position = EditorGUI.IndentedRect(position);

                        // Find/Bind the three properties
                        var textureProperty = property.FindPropertyRelative(nameof(texture));
                        var offsetProperty = property.FindPropertyRelative(nameof(offset));
                        var scaleProperty = property.FindPropertyRelative(nameof(scale));

                        // Calculate the positions and sizes of the fields to draw
                        var textureRect = new Rect(position.x, position.y + PREVIEW_SIZE * 0.5f - EditorGUIUtility.singleLineHeight * 0.5f, position.width - PREVIEW_SIZE, EditorGUIUtility.singleLineHeight);
                        var previewRect = new Rect(position.x + position.width - PREVIEW_SIZE, position.y, PREVIEW_SIZE, PREVIEW_SIZE);
                        var offsetRect = new Rect(position.x, position.y + previewRect.height, position.width, EditorGUIUtility.singleLineHeight);
                        var scaleRect = new Rect(position.x, offsetRect.y + EditorGUIUtility.singleLineHeight, position.width, EditorGUIUtility.singleLineHeight);

                        // The default texture field
                        EditorGUI.PropertyField(textureRect, textureProperty);

                        // using a grey texture as fallback if there is none referenced yet
                        var tex = textureProperty.objectReferenceValue ? (Texture)textureProperty.objectReferenceValue : Texture2D.grayTexture;
                        var texCoords = new Rect(offsetProperty.vector2Value.x, offsetProperty.vector2Value.y, 1 / scaleProperty.floatValue, 1 / scaleProperty.floatValue);
                        GUI.DrawTextureWithTexCoords(previewRect, tex, texCoords);

                        // The default vector2 field
                        EditorGUI.PropertyField(offsetRect, offsetProperty);

                        // The default float field with RangeAttribute applied
                        EditorGUI.PropertyField(scaleRect, scaleProperty);
                    }
                }
            }
        }
    }
#endif
}

我希望这是一个很好的起点,您可能需要尝试一下并根据您的需要弄清楚您想要将

scale
offset
应用到预览中的确切程度。


小演示

public class Example : MonoBehaviour
{
    public TextureSet test;
    public TextureSet[] tests;
}

© www.soinside.com 2019 - 2024. All rights reserved.