Search Unity

ScriptableObject asset, list names in inspector

Discussion in 'Immediate Mode GUI (IMGUI)' started by GisleAune, May 24, 2011.

  1. GisleAune

    GisleAune

    Joined:
    May 16, 2011
    Posts:
    88
    Okay, here's the deal. I have successfully managed to load, save and store data in a criptable object as I wanted to. One thing is bugging me though. When selecting my asset file, I get the list of items. How can I make it so I see the name-variable of every object in the list rather than Element 1, Element 2, etc...?
     
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    Generally, you can use a custom editor to define your own way of displaying an array object's data. Can you give any more detail about what you are doing with the object and how you would like the data to be displayed?
     
  3. GisleAune

    GisleAune

    Joined:
    May 16, 2011
    Posts:
    88
    I am learning the usage of editors and scriptable objects by making myself a RPG spell/talent tree editor. It saves a asset, which is an instance of a scriptable object. The asset contains then a List<Spell>, where it uses a [System.Serializable]Class Spell. In the inspector the list elements displays as Element 1, Element 2, etc. What I want is a string (the name) of the class instances composing the list.

    It's just a slight annoyance, about everything else works. When I get time -- I have two tests on both sides of the weekend -- I can polish and optimize it and release it for free.
     
  4. Daniel_Brauer

    Daniel_Brauer

    Unity Technologies

    Joined:
    Aug 11, 2006
    Posts:
    3,355
    I haven't tried it with List<T>, but for arrays the Unity inspector will use string names if the string is the first serializable member of the object. This is how custom GUIStyles are displayed by name when inspecting a GUISkin.
     
  5. GisleAune

    GisleAune

    Joined:
    May 16, 2011
    Posts:
    88
    That did it -- thank you.
     
  6. ianjosephfischer

    ianjosephfischer

    Joined:
    Mar 6, 2012
    Posts:
    13
    Here is a quick property attribute I made to do this.

    Code (csharp):
    1. /*
    2.  * Used to enumaerate array fields by an enum in the inspector.
    3.  */
    4. using System;
    5. using UnityEngine;
    6.  
    7. public class EnumerateArrayAttribute : PropertyAttribute
    8. {
    9.     public readonly Type enumType;
    10.  
    11.  
    12.     public EnumerateArrayAttribute(Type enumType)
    13.     {
    14.         if(!enumType.IsEnum)
    15.         {
    16.             Debug.LogError("Invalid Enum Type: " + enumType.ToString());
    17.         }
    18.         this.enumType = enumType;
    19.     }
    20. }
    And it's drawer.

    Code (csharp):
    1. using System;
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. [CustomPropertyDrawer(typeof(EnumerateArrayAttribute))]
    6. public class EnumerateArrayDrawer : PropertyDrawer
    7. {
    8.     #region Exposed
    9.  
    10.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    11.     {
    12.         int indentLevel = EditorGUI.indentLevel;
    13.         int num = indentLevel - property.depth;
    14.  
    15.         SerializedProperty serializedProperty = property.Copy();
    16.         SerializedProperty endProperty = serializedProperty.GetEndProperty();
    17.         position.height = base.GetPropertyHeight(serializedProperty, label);
    18.         EditorGUI.indentLevel = serializedProperty.depth + num - 1;
    19.  
    20.         serializedProperty.isExpanded = EditorGUI.Foldout(position, serializedProperty.isExpanded, label)  serializedProperty.hasVisibleChildren;
    21.  
    22.         position.y += position.height;
    23.         int propertyIndex = -1;
    24.         while(serializedProperty.NextVisible(serializedProperty.isExpanded)  !SerializedProperty.EqualContents(serializedProperty, endProperty))
    25.         {
    26.             EditorGUI.indentLevel = serializedProperty.depth + num;
    27.             position.height = EditorGUI.GetPropertyHeight(serializedProperty, null, false);
    28.             EditorGUI.BeginChangeCheck();
    29.             if(propertyIndex == -1
    30.                 || propertyIndex >= enumNames.Length)
    31.             {
    32.                 EditorGUI.PropertyField(position, serializedProperty);
    33.             }
    34.             else
    35.             {
    36.                 EditorGUI.PropertyField(position, serializedProperty, new GUIContent(enumNames[propertyIndex]));
    37.             }
    38.             if(EditorGUI.EndChangeCheck())
    39.             {
    40.                 break;
    41.             }
    42.             position.y += position.height;
    43.             ++propertyIndex;
    44.         }
    45.  
    46.         EditorGUI.indentLevel = indentLevel;
    47.     }
    48.  
    49.  
    50.     public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    51.     {
    52.         float extraHeight = 2.0f;
    53.  
    54.         if(!property.isExpanded)
    55.         {
    56.             return base.GetPropertyHeight(property, label) + extraHeight;
    57.         }
    58.  
    59.         float baseHeight = base.GetPropertyHeight(property, label);
    60.  
    61.         return baseHeight * 2f + property.arraySize * baseHeight + extraHeight;
    62.     }
    63.  
    64.     #endregion
    65.  
    66.     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    67.  
    68.     #region Internal
    69.  
    70.     private string[] _enumNames = null;
    71.  
    72.  
    73.     private string[] enumNames
    74.     {
    75.         get { return _enumNames != null ? _enumNames : _enumNames = Enum.GetNames((attribute as EnumerateArrayAttribute).enumType); }
    76.     }
    77.  
    78.  
    79.     #endregion
    80. }
    Here is an example of usage.

    Code (csharp):
    1. using System.Collections;
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4.  
    5. public class LevelMaterialMap : MonoBehaviour
    6. {
    7.     #region Exposed
    8.  
    9.     public Material this[int index]
    10.     {
    11.         get { return _materials[index]; }
    12.     }
    13.  
    14.     #endregion
    15.  
    16.     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    17.  
    18.     #region Internal
    19.  
    20.     [SerializeField]
    21.     [EnumerateArray(typeof(Glyph.Type))]
    22.     private Material[] _materials = new Material[4];
    23.  
    24.     [SerializeField]
    25.     [EnumerateArray(typeof(Glyph.Type))]
    26.     private List<Material> _listExample = new List<Material>();
    27.  
    28.     #endregion
    29. }