Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Error while using SerializeField and HideInInspector tags

Discussion in 'Editor & General Support' started by thrmotta, Dec 10, 2014.

  1. thrmotta

    thrmotta

    Joined:
    May 27, 2014
    Posts:
    32
    Hello!

    Im currently doing some heavy work at the Inspector Interface and Multiple Edition and every now and then I get some problem but nothing that I couldnt solve like this one.

    So I needed to serialize a Maskfield, and this http://forum.unity3d.com/threads/how-to-make-a-serializableproperty-with-a-maskfield.280702/ helped me with that. But in order to make this solution work I had to make a CallDefaultInspector call, which displays at the inspector all my public vars, which I dont want to.

    My first try was to put a [HideInInspector] tag on those vars, but since Im also serializing them, this caused this very strange error

    Code (CSharp):
    1. Invalid iteration - (You need to stop calling Next when it returns false)
    After some googling I couldnt find anything usefull related to this, so I just decided to try somethiing else, making then my vars to be private and with the tag [SerializeField], which makes them serializable but doesnt hide them from the Inspector. My next try was to use both tags [HideInInspector, SerializeField] to see how they worked togheter and this gave me the same error I had with the HideInInspector tag alone.

    So, what can be done to Serialize a variable while not displaying it at the Inspector?

    Why do I need this you ask, well, I have a component with a Mask Field where each field selected works like a bool to show a Vec3 field and I need this to work with the tag [CanEditMultipleObjects].

    This is my full Editor Class code:

    Code (CSharp):
    1.     using UnityEngine;
    2.     using System.Collections;
    3.     using System.Collections.Generic;
    4.     using UnityEditor;
    5.  
    6.     namespace SimVR
    7.     {
    8.         [CanEditMultipleObjects, CustomEditor(typeof(LinkActuator))]
    9.         public class LinkActuatorEditor : Editor
    10.         {
    11.  
    12.             private LinkActuator _script { get { return target as LinkActuator; }}
    13.  
    14.             int nInfo = 6;
    15.             string[] _infoNames = new string[6]{ "Linear Velocity",
    16.                                                 "Angular Velocity",
    17.                                                 "Linear Acceleration",
    18.                                                 "Angular Acceleration",
    19.                                                 "Force",
    20.                                                 "Torque" };
    21.          
    22.             SerializedProperty _functionsMaskProp;
    23.             Editor _functionsMaskEditor;
    24.  
    25.             SerializedProperty _linearVelocityProp;
    26.             SerializedProperty _angularVelocityProp;
    27.             SerializedProperty _linearAccelerationProp;
    28.             SerializedProperty _angularAccelerationProp;
    29.             SerializedProperty _forceProp;
    30.             SerializedProperty _torqueProp;
    31.  
    32.             SerializedProperty _chosenFunctionsProp;
    33.             //SerializedProperty _infoToApplyProp;
    34.  
    35.             void OnEnable()
    36.             {
    37.                 _functionsMaskProp = serializedObject.FindProperty("_functionsMask");
    38.  
    39.                 _linearVelocityProp         = serializedObject.FindProperty("_linearVelocity");
    40.                 _angularVelocityProp        = serializedObject.FindProperty("_angularVelocity");
    41.                 _linearAccelerationProp        = serializedObject.FindProperty("_linearAcceleration");
    42.                 _angularAccelerationProp     = serializedObject.FindProperty("_angularAcceleration");
    43.                 _forceProp                     = serializedObject.FindProperty("_force");
    44.                 _torqueProp                 = serializedObject.FindProperty("_torque");
    45.              
    46.                 _chosenFunctionsProp         = serializedObject.FindProperty("_chosenFunctions");
    47.                 //_infoToApplyProp   = serializedObject.FindProperty("_infoToApply");
    48.             }
    49.          
    50.          
    51.             public override void OnInspectorGUI ()
    52.             {
    53.                 DrawDefaultInspector ();
    54.                 serializedObject.Update ();
    55.                 EditorGUILayout.Space ();
    56.                 EditorGUILayout.Space ();
    57.              
    58.                 _chosenFunctionsProp.ClearArray ();
    59.                 for ( int i = 0; i < _infoNames.Length; i++ )
    60.                 {
    61.                     if( (_functionsMaskProp.intValue >> i & 0x1) == 1 )
    62.                     {
    63.                         _chosenFunctionsProp.arraySize++;
    64.                         SerializedProperty elementProperty = _chosenFunctionsProp.GetArrayElementAtIndex( _chosenFunctionsProp.arraySize - 1 );
    65.                         elementProperty.stringValue = _infoNames[i];
    66.                     }
    67.                 }
    68.              
    69.                 EditorGUILayout.Space ();
    70.              
    71.                 EditorGUI.indentLevel++;
    72.                 for( int i = 0; i < nInfo; i++ )
    73.                 {
    74.                     if( chosenFunctionsContains( _infoNames[i] ) )
    75.                     {                  
    76.                         switch ( i )
    77.                         {
    78.                         case 0:
    79.                             InterfaceEditor.CreateField( _linearVelocityProp,         _infoNames[0] );
    80.                             break;
    81.                         case 1:
    82.                             InterfaceEditor.CreateField( _angularVelocityProp,         _infoNames[1] );
    83.                             break;
    84.                         case 2:
    85.                             InterfaceEditor.CreateField( _linearAccelerationProp,     _infoNames[2] );
    86.                             break;
    87.                         case 3:
    88.                             InterfaceEditor.CreateField( _angularAccelerationProp,     _infoNames[3] );
    89.                             break;
    90.                         case 4:
    91.                             InterfaceEditor.CreateField( _forceProp,                 _infoNames[4] );
    92.                             break;
    93.                         case 5:
    94.                             InterfaceEditor.CreateField( _torqueProp,                 _infoNames[5] );
    95.                             break;
    96.                         }
    97.                     }
    98.                 }
    99.              
    100.                 EditorGUI.indentLevel--;
    101.  
    102.                 EditorGUILayout.Space ();
    103.              
    104.                 EditorGUILayout.BeginHorizontal();
    105.                 GUILayout.Space( 10 );
    106.                 if( GUILayout.Button ( "Apply" ) )
    107.                 {
    108.                     if( !Application.isPlaying )
    109.                         EditorUtility.DisplayDialog( "Error", "Só é possível aplicar essas funções com a simulação em andamento!", "Ok" );
    110.                     Debug.Log ( "targets.size: " + targets.Length );
    111.                     foreach( LinkActuator currLA in targets )              
    112.                     {
    113.                         if( currLA.getChosenFunctions().Count > 0 )
    114.                         {
    115.                             Debug.Log ( "Name: " + currLA.gameObject.transform.parent.name );
    116.                             Link linkScript = currLA.gameObject.GetComponent<Link>();
    117.                             for( int i = 0; i < nInfo; i++ )
    118.                             {
    119.                                 if( chosenFunctionsContains( _infoNames[i], currLA.getChosenFunctions() ) )
    120.                                 {
    121.                                     if      ( i == 0 )    { Debug.Log ( "_infoToApply.get( 0 ) ): " + currLA.getInfoToApply( i )  ); linkScript.ApplyLinearVelocity            ( currLA.getInfoToApply( i ) ); }
    122.                                     else if ( i == 1 )    linkScript.ApplyAngularVelocity         ( currLA.getInfoToApply( i ) );
    123.                                     else if ( i == 2 )    linkScript.ApplyLinearAcceleration         ( currLA.getInfoToApply( i ) );
    124.                                     else if ( i == 3 )    linkScript.ApplyAngularAcceleration     ( currLA.getInfoToApply( i ) );
    125.                                     else if ( i == 4 )    linkScript.ApplyForce                     ( currLA.getInfoToApply( i ) );
    126.                                     else if ( i == 5 )    linkScript.ApplyTorque                     ( currLA.getInfoToApply( i ) );
    127.                                 }
    128.                             }
    129.                         }
    130.                      
    131.                     }
    132.                 }
    133.                 EditorGUILayout.EndHorizontal();
    134.                 EditorGUILayout.Space ();
    135.                 serializedObject.ApplyModifiedProperties ();
    136.             }
    137.  
    138.             bool chosenFunctionsContains( string name, List<string> chosenFunctions )
    139.             {
    140.                 for ( int i = 0; i < chosenFunctions.Count; i++ )
    141.                 {
    142.                     if ( name == chosenFunctions[i] )
    143.                         return true;
    144.                 }
    145.              
    146.                 return false;
    147.             }
    148.  
    149.             bool chosenFunctionsContains( string name )
    150.             {
    151.                 for ( int i = 0; i < _chosenFunctionsProp.arraySize; i++ )
    152.                 {
    153.                     SerializedProperty elementProperty = _chosenFunctionsProp.GetArrayElementAtIndex( i );
    154.                     if ( name == elementProperty.stringValue )
    155.                         return true;
    156.                 }
    157.  
    158.                 return false;
    159.             }
    160.         }
    161.     }
    And my full regular class as of now:

    Code (CSharp):
    1.    using UnityEngine;
    2.     using System.Collections.Generic;
    3.    
    4.     namespace SimVR
    5.     {
    6.    
    7.         public class LinkActuator : MonoBehaviour
    8.         {      
    9.             [HideInInspector, SerializeField]
    10.             private Vector3 _linearVelocity = Vector3.zero;
    11.             [HideInInspector, SerializeField]
    12.             private Vector3 _angularVelocity = Vector3.zero;
    13.             [HideInInspector, SerializeField]
    14.             private Vector3 _linearAcceleration = Vector3.zero;
    15.             [HideInInspector, SerializeField]
    16.             private Vector3 _angularAcceleration = Vector3.zero;
    17.             [HideInInspector, SerializeField]
    18.             private Vector3 _force = Vector3.zero;
    19.             [HideInInspector, SerializeField]
    20.             private Vector3 _torque = Vector3.zero;
    21.    
    22.             [HideInInspector, SerializeField]
    23.             private List<string> _chosenFunctions = new List<string> ();      
    24.            
    25.             [GenericMask("Linear Velocity",
    26.                         "Angular Velocity",
    27.                         "Linear Acceleration",
    28.                         "Angular Acceleration",
    29.                         "Force",
    30.                         "Torque")]
    31.             public int _functionsMask = 0;
    32.    
    33.             public List<string> getChosenFunctions() { return _chosenFunctions; }
    34.             public Vector3 getInfoToApply(int idx)
    35.             {
    36.                 switch ( idx )
    37.                 {
    38.                 case 0:
    39.                     return _linearVelocity;
    40.                 case 1:
    41.                     return _angularVelocity;
    42.                 case 2:
    43.                     return _linearAcceleration;
    44.                 case 3:
    45.                     return _angularAcceleration;
    46.                 case 4:
    47.                     return _force;
    48.                 case 5:
    49.                     return _torque;
    50.                 default:
    51.                     Debug.LogError ( "Parametro de entrada incorreto!" );
    52.                     return Vector3.zero;
    53.                 }
    54.             }
    55.    
    56.             public void setInfoToApply( Vector3 infoToApply, int idx )
    57.             {
    58.                 switch ( idx )
    59.                 {
    60.                 case 0:
    61.                     _linearVelocity = infoToApply;
    62.                     break;
    63.                 case 1:
    64.                     _angularVelocity = infoToApply;
    65.                     break;
    66.                 case 2:
    67.                     _linearAcceleration = infoToApply;
    68.                     break;
    69.                 case 3:
    70.                     _angularAcceleration = infoToApply;
    71.                     break;
    72.                 case 4:
    73.                     _force = infoToApply;
    74.                     break;
    75.                 case 5:
    76.                     _torque = infoToApply;
    77.                     break;
    78.                 default:
    79.                     Debug.LogError ( "Parametro de entrada incorreto!" );
    80.                     break;
    81.                 }
    82.             }
    83.    
    84.             public void setInfoToApply( Vector3[] infoToApply )
    85.             {
    86.                 _linearVelocity = infoToApply[0];
    87.                 _angularVelocity = infoToApply[1];
    88.                 _linearAcceleration = infoToApply[2];
    89.                 _angularAcceleration = infoToApply[3];
    90.                 _force = infoToApply[4];
    91.                 _torque = infoToApply[5];
    92.             }
    93.    
    94.         }
    95.     }
    What can I do to make it work as intended?

    Thank you!
     
  2. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,716
  3. thrmotta

    thrmotta

    Joined:
    May 27, 2014
    Posts:
    32
    Enum will only allow me to choose one option on the dropdown list and I need to be able to choose more than one at the same time, which is why Im using a MaskField.

    And without the DrawDefaultInspector the MaskField (var _functionsMask ) wont be shown at the inspector.

    Here is a screenshot of the Script working without multiple edition:
    LinkActuator.png
    Are there other approaches to do this?
     
    Last edited: Dec 10, 2014
  4. thrmotta

    thrmotta

    Joined:
    May 27, 2014
    Posts:
    32
    I have also tried to put the EditorGUILayout.PropertyField, which is being called by the InterfaceEditor.CreateField method, at a new class with its own editor and then creating an Editor var to then call its OnInspectorGUI method, but with this approach I wasnt able to achieve the multiple edition.

    This is the code for that try:
    Code (CSharp):
    1. foreach ( LinkActuator currLA in targets )
    2.             {
    3.                 if ( currLA.GetComponent<FunctionsMask>() == null )
    4.                 {
    5.                     currLA.gameObject.AddComponent<FunctionsMask>();
    6.                 }
    7.  
    8.                 currLA._infoToApply = currLA.GetComponent<FunctionsMask>();
    9.                 currLA._infoToApply.hideFlags = HideFlags.None;
    10.  
    11.                 currLA._infoToApply._functionsMask = _functionsMaskProp.intValue;
    12.  
    13.             }
    14.  
    15.             _functionsMaskEditor = Editor.CreateEditor( _script._infoToApply );
    16.             if ( _functionsMaskEditor != null )
    17.                 _functionsMaskEditor.OnInspectorGUI();
    The problem here was the Editor.CreateEditor( _script._infoToApply ); call, where I couldnt think of way to call CreateEditor for each LinkActuator selected and only draw it on its interface. If i just put those 3 last lines inside the foreach Ill get several OnInspectorGUI calls at the same Component
     
  5. thrmotta

    thrmotta

    Joined:
    May 27, 2014
    Posts:
    32
    So, Im feeling very idiot right now..
    After what @LightStriker said, I tried the following line of code, which worked great:
    Code (CSharp):
    1. _functionTypeProp.intValue = (int)(LinkActuator.FunctiontTypes)EditorGUILayout.EnumMaskField( "Functions Mask", (LinkActuator.FunctiontTypes)_functionTypeProp.intValue );
    The only downside is that I dont get a "-" showing up at the EnumMaskField when there are multiple Gameobjects selected and they have different values, but besides that, this solves my problem.

    Thank you @LightStriker for the hint!
     
  6. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,716
    My pleasure.

    I dumped SerializedObject and SerializedProperty a long time ago, they tend to be too touchy in edge-cases.