Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

Property Drawer on elements of an array changing all elements.

Discussion in 'Immediate Mode GUI (IMGUI)' started by LMan, Jan 10, 2017.

  1. LMan

    LMan

    Joined:
    Jun 1, 2013
    Posts:
    491
    I have a property drawer that is supposed to allow the selection of animator parameters from an enumPopup.


    Code (CSharp):
    1. [CustomPropertyDrawer(typeof(Reaction))]
    2. [CanEditMultipleObjects]
    3. public class ReactionDrawer : PropertyDrawer
    4. {
    5.     AnimatorController animCntrl;
    6.     AnimatorControllerParameter[] parameters;
    7.     string[] parameter_names = new string[0];
    8.     int selectedParameter = 0;
    9.  
    10.     // Draw the property inside the given rect
    11.     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    12.     {
    13.        if(animCntrl == null)
    14.         {
    15.             if(Selection.activeGameObject != null)
    16.             {
    17.                 animCntrl = (AnimatorController)Selection.activeGameObject.GetComponent<Animator>().runtimeAnimatorController;
    18.             }
    19.             else
    20.             {
    21.                 return;
    22.             }
    23.                      
    24.             _init(); //populates the parameter and parameter names array
    25.         }
    26.         SerializedProperty parameter = property.FindPropertyRelative("parameter");
    27.         SerializedProperty type = property.FindPropertyRelative("type");
    28.  
    29.         // Using BeginProperty / EndProperty on the parent property means that
    30.         // prefab override logic works on the entire property.
    31.         EditorGUI.BeginProperty(position, label, property);
    32.  
    33.         // Draw label
    34.         position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
    35.  
    36.         var paramRect = new Rect(position.x, position.y, position.width/2, position.height);
    37.         var typeRect = new Rect(position.x + position.width/2 + 5, position.y, position.width/4, position.height);
    38.         var valRect = new Rect(position.x + (position.width/4)*3 + 5 , position.y, position.width/4, position.height);
    39.  
    40.         if (parameters.Length > 0)
    41.         {
    42.             selectedParameter = EditorGUI.Popup(paramRect, selectedParameter, parameter_names);
    43.             parameter.stringValue = parameters[selectedParameter].name;
    44.             SetParameterType(type);
    45.             EditorGUI.LabelField(typeRect, type.enumDisplayNames[type.enumValueIndex]);
    46.             DrawValueField(valRect, property);
    47.         }
    48.         else
    49.         {
    50.             EditorGUI.LabelField(new Rect(position.x, position.y, position.width, position.height), "No parameters found in Animator Controller");
    51.         }
    52.         EditorGUI.EndProperty();
    53.        
    54.     }
    The Reaction Property itself:
    Code (CSharp):
    1. [System.Serializable]
    2. public class Reaction
    3. {
    4.     public enum reactionType {boolean = 0, trigger = 1, integer = 2, floating = 3 , none = 4};
    5.  
    6.     public reactionType type = reactionType.none;
    7.     public string parameter;
    8.  
    9.     //rather than fool with types, keep them all.
    10.     public bool value_bool;
    11.     public int value_int;
    12.     public float value_float;
    13. }
    Pictured, you see the Reactor component, which keeps an array of Reactions.
    Reaction property Drawer.png

    What happens is that when I change the popup value in one box, it changes for all the elements in the array. What am I missing?
     
  2. CDF

    CDF

    Joined:
    Sep 14, 2013
    Posts:
    713
    maybe put a BeginChangeCheck and EndChangeCheck around setting the parameter.stringValue.
    "selectedParameter" is probably being re-used.

    Code (CSharp):
    1. EditorGUI.BeginChangeCheck();
    2.  
    3. int newSelectedParameter = EditorGUI.Popup(paramRect, selectedParameter, parameter_names);
    4.  
    5. if (EditorGUI.EndChangeCheck()) {
    6.  
    7.     selectedParameter = newSelectedParameter;
    8.     parameter.stringValue = parameters[selectedParameter].name;
    9.     SetParameterType(type);
    10. }
     
  3. LMan

    LMan

    Joined:
    Jun 1, 2013
    Posts:
    491
    Aha, I found the answer in another thread at last.

     
  4. LMan

    LMan

    Joined:
    Jun 1, 2013
    Posts:
    491
    At the moment, my solution is just to keep an int in the reaction property for recalling the index.
     
  5. mo_star

    mo_star

    Joined:
    Jul 2, 2014
    Posts:
    1
    Hey man I know its old topic, but could you elaborate how you achieved this. Where did you hold the reference to reactive property? I tried putting the reactive property inside the propertydrawer and it still does the same thing.

    I'm creating some custom editors and they are really pain in the butt. Took me 3 days to figure out the workflow of the editor creation code.

    Please help !!!

    Thanks in advance,
    Miran
     
  6. NolwennB

    NolwennB

    Joined:
    Mar 4, 2014
    Posts:
    15
    What I did, based on what LMan said :
    In your serializable class add
    public int index;

    In your PropertyDrawer, replace
    selectedParameter
    with
    property.FindPropertyRelative("index").intValue

    It works for me!
     
  7. BinaryCats

    BinaryCats

    Joined:
    Feb 8, 2016
    Posts:
    162
    What I do is parse the full path of the property, looking for "Array.Data[x]", and grab the value of x, and that is the index of the thing being drawn