Search Unity

  1. Improved Prefab workflow (includes Nested Prefabs!), 2D isometric Tilemap and more! Get the 2018.3 Beta now.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice
  4. Want to see the most recent patch releases? Take a peek at the patch release page.
    Dismiss Notice

Property Drawer on elements of an array changing all elements.

Discussion in 'Extensions & OnGUI' started by LMan, Jan 10, 2017.

  1. LMan

    LMan

    Joined:
    Jun 1, 2013
    Posts:
    473
    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:
    628
    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:
    473
    Aha, I found the answer in another thread at last.

     
  4. LMan

    LMan

    Joined:
    Jun 1, 2013
    Posts:
    473
    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:
    6
    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:
    129
    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