Michał Lorenc
Michał Lorenc

Reputation: 3

Unity editor script that will make a visual object field for an array element and will let me edit it

I have a script in which I have declared an array of sprites. I want to represent it in a nice way in the editor and don't want to make it noticeable that it's an array.

This is what my script looks like:

public class SkinData : ScriptableObject
{
    public Sprite[] FaceDownSprites = new Sprite[MaxFrameCount];
}

And this is what the editor script looks like:

[CustomEditor(typeof(SkinData))]
public class SkinDataEditor : UnityEditor.Editor
{
    private const float SpriteFieldSize = 100f;

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();
        SkinData skinData = (SkinData)target;

        GUILayout.Label("Tilesheet");
        EditorGUILayout.BeginHorizontal();
        EditorGUILayout.ObjectField(skinData.FaceDownSprites[0], typeof(Sprite), GUILayout.Height(SpriteFieldSize), 
        GUILayout.Width(SpriteFieldSize));
        GUILayout.Width(SpriteFieldSize));
        EditorGUILayout.ObjectField(skinData.FaceDownSprites[1], typeof(Sprite), GUILayout.Height(SpriteFieldSize),
        GUILayout.Width(SpriteFieldSize));
        EditorGUILayout.ObjectField(skinData.FaceDownSprites[2], typeof(Sprite), GUILayout.Height(SpriteFieldSize),
        GUILayout.Width(SpriteFieldSize));
        EditorGUILayout.EndHorizontal();
    }
}

This is how it looks to give you an idea of what I wanted to achieve, the arrays won't be visible in the final version

The problem is it works only partially, it shows the sprites from the array in the newly created fields, but it doesn't let me edit/add sprites. Nothing happens when I drag and drop the sprite to the new field. It doesn't change in the array as well. Any idea how to make it work?

Upvotes: 0

Views: 501

Answers (2)

derHugo
derHugo

Reputation: 90813

Expanding on this answer

In general you want to avoid directly going through the target at all!

This can yield quite some complexity regarding dirty marking and undo/redo handling, prefab overrides, etc.

Rather try to stick to SerializedProperty as much as possible and do e.g.

[CustomEditor(typeof(SkinData))]
public class SkinDataEditor : Editor
{
    private const float SpriteFieldSize = 100f;

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        GUILayout.Label("Tilesheet", EditorStyles.boldLabel);
        
        serializedObject.Update();

        using (new EditorGUILayout.HorizontalScope())
        {
            var spritesProperty = serializedObject.FindProperty(nameof(SkinData.FaceDownSprites));

            if (spritesProperty.arraySize < 3)
            {
                spritesProperty.arraySize = 3;
            }

            for (var i = 0; i < 3; i++)
            {
                 spritesProperty.GetArrayElementAtIndex(i).objectReferenceValue = EditorGUILayout.ObjectField(spritesProperty.GetArrayElementAtIndex(i).objectReferenceValue, typeof(Sprite), false, GUILayout.Height(SpriteFieldSize), GUILayout.Width(SpriteFieldSize));
            }
        }

        serializedObject.ApplyModifiedProperties();
    }
}

Upvotes: 0

Yusuf
Yusuf

Reputation: 86

This method:

EditorGUILayout.ObjectField();

returns the object that you have just assigned. So if you want to keep changes, you should do this:

skinData.FaceDownSprites[0] = (Sprite) EditorGUILayout.ObjectField(skinData.FaceDownSprites[0], typeof(Sprite), GUILayout.Height(SpriteFieldSize), GUILayout.Width(SpriteFieldSize));

And also if you are doing changes on the assets, research these: https://docs.unity3d.com/ScriptReference/EditorUtility.SetDirty.html https://docs.unity3d.com/ScriptReference/AssetDatabase.SaveAssetIfDirty.html https://docs.unity3d.com/ScriptReference/AssetDatabase.SaveAssets.html

Upvotes: 0

Related Questions