Search Unity

[SOLVED] Custom inspector - vars in nested classes - System.Serializable

Discussion in 'Scripting' started by Mr_Albert, Jun 16, 2017.

  1. Mr_Albert

    Mr_Albert

    Joined:
    Apr 28, 2017
    Posts:
    25
    Hi pro! I have new noob stupid question for you (i am sorry)

    I read different post on the web and try any way but i not understand... "anything"!

    this is my situation:

    inside the file whit var:
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. namespace Libs_playerController.program
    7. {
    8.  
    9.     public partial class PlayerController : MonoBehaviour
    10.     {
    11.  
    12.         [System.Serializable]
    13.         class getVars : PlayerController
    14.         {
    15.             public GameObject OrbitingGroup;
    16.             myvar...
    17.         }
    18.  
    19.     }
    20. }
    21.  
    and in the editor folder I have other file, this:

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6. using UnityEditor;
    7.  
    8. namespace Libs_playerController.program
    9. {
    10.    public partial class PlayerController : MonoBehaviour
    11.    {
    12.  
    13.        [CustomEditor(typeof(PlayerController))]
    14.        public class editedInspector : Editor
    15.        {
    16.            public override void OnInspectorGUI()
    17.            {
    18.  
    19.                getVars getVars = new getVars();  // not working...
    20.  
    21.                PlayerController PlayerController = target as PlayerController;
    22.              
    23.               getVars.OrbitingGroup  = (GameObject)EditorGUILayout.ObjectField("ORBITING:", getVars.OrbitingGroup, typeof(GameObject), true); // not working
    24.  
    25.               and... var test not working....
    26.  
    27.              and...other test not working...
    28.  
    29.              can't see any var.
    30.  
    31.           }
    32.       }
    33.   }
    34. }
    35.  
    36.  
    now... what i can do for take and use the vars????

    thank you for help!
     
  2. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    @Mr_Albert

    Hi, I'm not that much familiar with editor scripting,

    EDIT: sorry, if the question is specific to nested classes...my answer don't help with that.

    but have done some tinkering with them...

    also, not sure what you are doing with those partial classes and everything...

    Here is an example how to get data from class in custom inspector.
    I used your code as template, and modified it:

    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class PlayerController : MonoBehaviour
    7. {
    8.     public GameObject OrbitingGroup;
    9.     public float myVar = 123;
    10. }
    11.  
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEditor;
    6.  
    7. [CustomEditor(typeof(PlayerController))]
    8. public class PlayerControllerEditor : Editor
    9. {
    10.     public override void OnInspectorGUI()
    11. {
    12.         // Draw default inspector stuff
    13.         DrawDefaultInspector();
    14.  
    15.         // Get target class,  get class this editor is for
    16.         PlayerController myTarget = (PlayerController)target;
    17.  
    18.         // Get fields from target class
    19.         GameObject myObject = myTarget.OrbitingGroup;
    20.         float myVar = myTarget.myVar;
    21.  
    22.         // Do something with data you got from target class - Show gameobjects name...
    23.         EditorGUILayout.LabelField("myVar gameObject's name", myTarget.name);
    24.  
    25.         // Or show and edit its values
    26.         myTarget.myVar = EditorGUILayout.FloatField(myTarget.myVar);
    27.  
    28.         // Or edit values directly, like this using serialized property, no need to "put it back" to itself
    29.         serializedObject.Update();
    30.         SerializedProperty serializedPropMyVar = serializedObject.FindProperty("myVar");
    31.         EditorGUILayout.PropertyField(serializedPropMyVar);
    32.         serializedObject.ApplyModifiedProperties();
    33.     }
    34. }
    35.  

    Unity has some really good tutorials on the subject of custom inspectors, better check at least this one:

    https://unity3d.com/learn/tutorials/topics/interface-essentials/building-custom-inspector
     
    Last edited: Jun 16, 2017
    AdmiralThrawn and Mr_Albert like this.
  3. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    916
    there's a couple of ways you can choose to do this:
    • Have Unity handle this for you
    • Have the Editor for the PlayerController handle this.
    • Write a PropertyDrawer for the getVars
    first off, getVars is a nested class. so to access it you'll need to traverse to it
    Code (CSharp):
    1. var getVars = new PlayerController.getVars();
    this'll work... but don't put that into OnInspectorGUI, you'll end up creating a new getVar Instance every time the inspector is repainted. Inside your partial class have a public or SerilizableField for getVar
    Code (CSharp):
    1. public partial class PlayerController : MonoBehaviour
    2.     {
    3.         [System.Serializable]
    4.         // by the way name your classes correctly
    5.         class GetVars : PlayerController
    6.         {
    7.             public GameObject OrbitingGroup;
    8.             myvar...
    9.         }
    10.         [SerializeField] private GetVars getVar;
    11.     }
    at this point you don't have to do anything else Unity should find and show it in the inspector

    next up:
    Code (CSharp):
    1.  
    2. // this partial is bad juju
    3.  public partial class PlayerController : MonoBehaviour
    4.    {
    5.      
    6.        [CustomEditor(typeof(PlayerController))]
    7.        public class editedInspector : Editor {}
    8.   }
    editor-scripting Code should be placed in the Editor Folder. because of this your edited Inspector will end up part of a different assembly. and the two Partials will not see each other. a partial class will only link up with other partial classes in the same assembly. what would happen here is that you'll end up with two PlayerController classes across 2 assemblies, instead of 1 PlayerController class across 2 assemblies, and that'll bring other difficulties as now the PlayerController references you use in the Editor assembly won't ever reference the PlayerController class in the other assembly (just its own).

    simply put, don't nest your Editor classes inside partials.

    it can be useful. one example I've seen it used is where classes in an SDK are made partial. Then when imported into a game, the game can create extra partials of the same class to extend those classes, without modifying the base class. Which avoids all sorts of issues when importing an SDK version update via things like UnityPackage which normally would clobber your game-specific changes.
     
    eses and Mr_Albert like this.
  4. Mr_Albert

    Mr_Albert

    Joined:
    Apr 28, 2017
    Posts:
    25
    JoshuaMcKenzie
    eses


    ok, thank you.

    I answer of your questions

    A) I created a player movement and view controller (whit delay and all for player interaction and animation) similar to gear of war. I want to serialize the classes because unity resets the var on play... But as you can see I have a strange stupidity in understanding what does not work hehehe

    B) I use the partial class for subdivide the script in differente file in this mode:

    • myPlayerControllerPlugin/script.cs
    • myPlayerControllerPlugin/Core/alltaskandfunction.cs
    • myPlayerControllerPlugin/Core/allvar.cs

      and...
    • myPlayerControllerPlugin/Editor/Editor.cs
    • myPlayerControllerPlugin/Resources/...image etc
    ( If it isn't perfect organized I become crazy )
    If I remove the var class, excluding the reset on play, it works all to great but it's also true that I have to figure out what I'm wrong about as a real noob idiot, or I never learn.



    I'm trying to change by following your advice (and thank you so much)

    now...

    the new situation:

    allvar.cs
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. namespace Libs_playerController.program
    7. {
    8.  
    9.    public partial class PlayerController : MonoBehaviour
    10.    {
    11.  
    12.        [System.Serializable]
    13.        class VarList : PlayerController
    14.        {
    15.  
    16.            public GameObject OrbitingGroup;
    17.           other vars
    18.  
    19.        }
    20.        [SerializeField] private VarList GetVar;
    21.  
    22.    }
    23.  
    24. }
    25.  
    in all function, for now, it's all ok. take all :)

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. namespace Libs_playerController.program
    7. {
    8.  
    9.    public partial class PlayerController : MonoBehaviour
    10.    {
    11.  
    12.  
    13.        //view, view cut, cam coolider and other
    14.        public void OrbitController()
    15.        {
    16.  
    17.            //get var...
    18.            var GetVar = new PlayerController.VarList();
    19.  
    20.           and start the task and function etcc... al good.
    21.  
    22.       }
    23.  
    24. }
    25.  
    GREAT but...


    Editor.cs dont see anything...
    I try all and I m going crazy man, really

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6. using UnityEditor;
    7.  
    8. using Libs_playerController.program;
    9. namespace Libs_playerController.editor
    10. {
    11.  
    12.    [CustomEditor(typeof(PlayerController))]
    13.    public class editedInspector : Editor
    14.    {
    15.        public override void OnInspectorGUI()
    16.        {
    17.  
    18.            PlayerController PlayerController = (PlayerController)target;
    19.  
    20.            //var GetVar = new PlayerController.VarList(); // not working
    21.  
    22.           getVar.OrbitingGroup = (GameObject)EditorGUILayout.ObjectField("ORBITING:", getVar.OrbitingGroup, typeof(GameObject), true);
    23.            Other...
    24.  
    25.        }
    26.  
    27.    }
    28.  
    29. }
    30.  
    the message:

    Assets/player controller/Editor/Editor.cs(117,56): error CS1061: Type `Libs_playerController.program.PlayerController' does not contain a definition for `GetVar' and no extension method `GetVar' of type `Libs_playerController.program.PlayerController' could be found. Are you missing an assembly reference?

    or

    Assets/player controller/Editor/Editor.cs(23,38): error CS0426: The nested type `VarList' does not exist in the type `Libs_playerController.program.PlayerController'

    "FACEPALM"


    please... help.
     
    Last edited: Jun 16, 2017
  5. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    916
    so when I said "have a public or SerilizableField for getVar" I showed the SerializeField example. and I made it private. doing so its not normally accessible via direct reference. What unity would do is it would grab the property via reflection and draw it as a Serializaable Property.

    The suggested way to access your class is through FindProperty.
    Code (CSharp):
    1. var p_getVars = serializableObject.FindProperty("getVars");
    2. EditorGUILayout.PropertyField(p_getVars);
    its not the only way to draw the field but it does reduce a lot of the default grunt work and adds bonus features such as Undo.

    now if you're set on how you want the Editor to work you can simple make the field public.

    Also: I didn't notice this eariler, but VarList doesn't have a defined accessor, so its assumed to be a private class, which is also why you can't access it.

    Also also: you defined your variable as "GetVar" but you're trying to use it as "getVar". C# is case-sensitive.
     
  6. Mr_Albert

    Mr_Albert

    Joined:
    Apr 28, 2017
    Posts:
    25
    The mystery, however, becomes more dense
    I reset for create a backup my script and and now no longer resets var (WTF??)
    It showed all var and at the same time the cusom editor ("with two PlayerController classes across 2 assemblies" situation? bah!)
    [HideInInspector] on the public standard var... i see only the custom editor and it work.


    now, for the serialization of var... nothing... not working.

    before the editor - the function not see the class so the class declaration or navigation is wrong or
    Or it is, however, incomplete or incalculable or static

    Assets/player controller/Core/Vars_OrbitController.cs(44,35): error CS0052: Inconsistent accessibility: field type `Libs_playerController.program.PlayerController.VarList' is less accessible than field `Libs_playerController.program.PlayerController.GetVar'

    I not have any ideas because not see the class..........

    I'm not an expert but I find it absurd not to get into a nested class and let me return what's inside...
     
  7. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    916
    Like I said, you've made the class private so the compiler is preventing access to it when you attempt to pass it outside the class

    and Like I said. Don't wrap your editor classes in partials. As far as the Compiler is concerned your partials is just two classes with the same name but in different Assemblies, Like UnityEngine.Object and System.Object. they have the same name, but they exist in different dlls with different namespaces, so they are different classes. in other words, your Editor can't access private fields in the other PlayerController partials.

    there's ways to use partials, but this isn't the correct way to use it with Editor scripting.
     
  8. Mr_Albert

    Mr_Albert

    Joined:
    Apr 28, 2017
    Posts:
    25
    The good news is that there are almost.

    With the new fixes I did correct almost everything.

    I'm trying to delete the partial but i have not idea how to merge the files ...

    Coming from web development for me it's absurd to have it all in one file

    I'm trying I'm trying I'm trying I'm trying....
     
    Last edited: Jun 17, 2017
  9. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    916
    I never said you need it all in one file or that you need to merge it, I said don't put the Editor to inside the PlayerController. All your other Partials are fine its just the Editor thats the problem

    Think of it in terms of MCV. your MonoBehaviour is the model/Controller (in that it stores the data and manages it) your Editor/EditorWindow/PropertyDrawer is the View (in that its an interface to show the data). the View should be separate from the model/controller. Editor classes are there to only draw the fields in the inspector, it shouldn't own the data. You're making the PlayerController take up way more responsibilities than it should.
     
  10. Mr_Albert

    Mr_Albert

    Joined:
    Apr 28, 2017
    Posts:
    25
    I love all today....

    IT WORK!


    Now ...
    This works like this:

    All the variables (for now public) are in a single file, ordered and with their specific class

    Code (CSharp):
    1.  
    2. //VarList.cs All vars
    3.  
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using UnityEngine;
    7.  
    8. namespace MyScriptName.program
    9. {
    10.      public partial class MyScriptName: MonoBehaviour
    11.     {
    12.  
    13.         [System.Serializable]
    14.         public class VarList //not extend this or all is null
    15.         {
    16.  
    17.                public GameObject MyCameraOrOther;
    18.                public float myvarone= 2.0f;
    19.                public float myvartwo= 1.5f;
    20.                public float myvarthree= 1.0f;
    21.                Other...
    22.  
    23.        }
    24.        [SerializeField] public VarList GetVar;
    25.  
    26.     }
    27. }
    28.  

    Finally, all tasks reach the var class (only the public)

    Code (CSharp):
    1.  
    2. //TaskOne.cs or other task files...
    3.  
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using UnityEngine;
    7.  
    8. namespace MyScriptName.program
    9. {
    10.      public partial class MyScriptName: MonoBehaviour
    11.     {
    12.  
    13.      
    14.               public void MyTaskA()
    15.               {
    16.                  GetVar.MyCameraOrOther.trans.........;
    17.                  other...
    18.               }
    19.  
    20.               public void MyTaskB()
    21.               {
    22.                  other...
    23.               }
    24.                  other tasks...
    25.  
    26.     }
    27. }
    28.  

    And main file is clear whit only a tasks...
    Code (CSharp):
    1.  
    2. //MainFile.cs
    3.  
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using UnityEngine;
    7.  
    8. namespace MyScriptName.program
    9. {
    10.      public partial class MyScriptName: MonoBehaviour
    11.     {
    12.      
    13.               void Start ()
    14.               {
    15.                  MyTaskA();
    16.                  Other...
    17.               }
    18.  
    19.               void Update()
    20.               {
    21.                  MyTaskB();
    22.                  Other...
    23.  
    24.               }
    25.  
    26.     }
    27. }
    28.  
    In the custom editor:
    Code (CSharp):
    1.  
    2. //Editor.cs or other task file
    3.  
    4. using UnityEngine;
    5. using UnityEditor;
    6.  
    7. using MyScriptName.program;
    8. namespace MyScriptName.editor
    9. {
    10.  
    11.     [CustomEditor(typeof(MyScriptName))]
    12.     //[CanEditMultipleObjects] If you need it
    13.     public class MyScriptNameEditor : Editor
    14.     {
    15.  
    16.              public override void OnInspectorGUI()
    17.              {
    18.  
    19.                         MyScriptName MyScriptName= target as MyScriptName;
    20.  
    21.                        //DrawDefaultInspector(); (Shows standard var)
    22.  
    23.                         MyScriptName.GetVar.MainCameraOrOther = (GameObject)EditorGUILayout.ObjectField("A LABEL:", MyScriptName.GetVar.MainCameraOrOther, typeof(GameObject), true);
    24.  
    25.                         other...
    26.  
    27.              }
    28.    }
    29. }
    30.  

    Finally it work


    ya... the var si public and it isn't good... now try to change the situaton.

    thanks for help man!