unity-game-engineunity-editor

Unity property dropdown changes all values of array


I want to do a dropdown menu that works similar to the tag system but for my sound names. However, whenever I have my custom properties in a container and I change one of them, every other property also changes.

This is my property drawer code:

using UnityEditor;
using UnityEngine;

[CustomPropertyDrawer(typeof(SoundName))]
public class SoundNamePropertyDrawer : PropertyDrawer
{
    SoundNamesContainer _soundNamesContainer;
    SerializedProperty _nameProperty;
    SerializedProperty _indexProperty;

    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        if(_nameProperty == null)
        {
            _nameProperty = property.FindPropertyRelative("Name");
            _indexProperty = property.FindPropertyRelative("index");
        }
        if(_soundNamesContainer == null)
            _soundNamesContainer = Resources.Load("SoundNames") as SoundNamesContainer;

        EditorGUI.BeginProperty(position, label, property);
        _indexProperty.intValue = EditorGUI.Popup(position, _indexProperty.intValue, _soundNamesContainer.Names);
        _nameProperty.stringValue = _soundNamesContainer.Names[_indexProperty.intValue];
        
        EditorGUI.EndProperty();
    }

    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return EditorGUIUtility.singleLineHeight;
    }
}


Solution

  • For arrays/lists the same instance of the drawer is used for all items!

    So instead of

    if(_nameProperty == null)
    {
        _nameProperty = property.FindPropertyRelative("Name");
        _indexProperty = property.FindPropertyRelative("index");
    }
    

    you should just use

    _nameProperty = property.FindPropertyRelative("Name");
    _indexProperty = property.FindPropertyRelative("index");
    

    otherwise you will always use the cached first item property for the entire collection.

    The performance overhead for getting the properties repeatedly should actually be quite neglectable ;)

    I wouldn't even store them in a class field since the same kind of issues could then occurre if you begin to use the properties also within GetPropertyHeight.

    It makes sense in an Editor but within a PropertyDrawer (imho) it's always best to just get and store the properties within the methods where needed.