0
\$\begingroup\$

I have created following classes for my game in unity:

[System.Serializable]
 public class abstract BaseA {
 }

 [System.Serializable]
 public class DeriveABaseA : BaseA {
 }

 [System.Serializable]
 public class DeriveBBaseA : BaseA {
 }

 [System.Serializable]
 public class abstract BaseB {
     public int Type = 0;
     public int AType;
     public BaseA A;
 }

 [System.Serializable]
 public class DerivedABaseB : BaseB {
     DerivedABaseB() {
         Type = 1;
     }
 }

 [System.Serializable]
 public class DerivedBBaseB : BaseB {
     public DerivedBBaseB() {
         Type = 2;
     }
 }

 [System.Serializable]
 public class ClassC {
     public int BType;
     public BaseB B;
 }

 public class ClassD : MonoBehaviour {
     public List<ClassC> C;
 }

now, I'm trying to add my custom editor for them. this is the first time I'm using editor scripting and I have few question regarding how to add custom editor scripts for my classes:

  • What is the correct way of adding new element to variable C
  • How can I call PropertyDrawer for ClassC when I'm drawing C elements?
  • How to initialize variable B of class ClassC based on the user entered value for variable BType in class ClassC?
  • How can I call DerivedABaseBPropertyDrawer or DerivedBBaseBPropertyDrawer based on type of variable B in class ClassC?
  • How to initialize variable A of class ClassB based on the user entered value for variable AType in class ClassB?

This is code code that I was able to get it to work except for 2nd and last question:

[CustomEditor(typeof(ClassD))]
 public class ClassDEditor : Editor {
     ClassD m_target;
     public override void OnInspectorGUI()
     {
         m_target = (ClassD)target;
         if (GUILayout.Button("Add"))
         {
             //Is this the correct way of adding value to this list?
             m_target.C.Add(new ClassC());
         }

         foreach(var c in m_target.C) {
             //How propertydrawer can be called for each element of C?
         }
     }
 }

 [CustomPropertyDrawer(typeof(ClassC))]
 public ClassCPropertyDrawer : PropertyDrawer {
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
     {
         //Is the following code valid (it's working) and is there a cleaner/simpler way of doing this?
         object obj = fieldInfo.GetValue(property.serializedObject.targetObject);
         var index = System.Convert.ToInt32(new string(property.propertyPath.Where(c => char.IsDigit(c)).ToArray()));
         ClassC objC = ((List<ClassC>)obj)[index];
         if(objC.BType == 1 && typeof(objC.B) != typeof(DerivedABaseB)) {
             objC.B = new DerivedABaseB();
         } else {
             objC.B = new DerivedBBaseB();
         }
     }
 }

 [CustomPropertyDrawer(typeof(ClassB))]
 public ClassBPropertyDrawer : PropertyDrawer {
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
     {
         //How to get access to B instance object
         var type   = property.FindPropertyRelative("Type").intValue;
         var a_type = property.FindPropertyRelative("AType").intValue;
         var drawer = null;

         if(type == 1) {
             drawer = new DerivedABaseBPropertyDrawer();
         } else {
             drawer = new DerivedBBaseBPropertyDrawer();
         }
         if(a_type == 1) {
             //Set A == new DeriveABaseA();
         } else {
             //Set A == new DeriveBBaseA();
         }

     }
 }

 [CustomPropertyDrawer(typeof(DerivedABaseB))]
 public DerivedABaseBPropertyDrawer : PropertyDrawer {
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
     {

     }
 }

 [CustomPropertyDrawer(typeof(DerivedBBaseB))]
 public DerivedBBaseBPropertyDrawer : PropertyDrawer {
     public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
     {

     }
 }
\$\endgroup\$
  • 2
    \$\begingroup\$ The particular example you've shown might not be possible in Unity - its serialization system does not fully handle polymorphism, so if you have a list of type Z containing instances of types X & Y which derive from Z, after saving & loading you'll just have a list of type Zs (and if Z is abstract you get nulls). The derived type information is not saved & loaded. But there's probably still a way to achieve the feature / end goal you want, if you can tell us more about that. Right now this example is so abstracted that it's hard to guess what kinds of alternatives we should try proposing. \$\endgroup\$ – DMGregory Dec 8 '18 at 18:22
  • \$\begingroup\$ @DMGregory I have few different classes which generates different random points (in circle, in sphere, etc), now I need to instantiate one of them based on an enum value but I want my custom editor to gets updated based on a dropdown selection. each of these classes also have different settings that need to be saved and used on the runtime but I cannot find a way to do this. \$\endgroup\$ – Masoud Dec 10 '18 at 13:56
  • 1
    \$\begingroup\$ Have you considered making these types MonoBehaviours or ScriptableObjects? Unity correctly handles polymorphism for those two cases. \$\endgroup\$ – DMGregory Dec 10 '18 at 14:16
  • \$\begingroup\$ I haven't tried that but I'm going to try it, do I need to instantiate the objects using CreateInstance in my Editor script? \$\endgroup\$ – Masoud Dec 10 '18 at 14:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.