Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Unity Reflection custom class

Discussion in 'Scripting' started by padami, Jul 29, 2020.

  1. padami

    padami

    Joined:
    May 19, 2015
    Posts:
    8
    Hello everyone!

    I have a problem with a scriptable object that i want to foreach through in another script.
    I've made some custom serializable classes in the scriptable object.

    This is my scriptable object.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. // Class which holds all the different part types
    6. [System.Serializable]
    7. public class Types
    8. {
    9.     public string name;
    10. }
    11.  
    12. // Class containing all the body types
    13. [System.Serializable]
    14. public class Bodies
    15. {
    16.     public string id;
    17.     public GameObject prefab;
    18. }
    19.  
    20. // Class containing all the battery types
    21. [System.Serializable]
    22. public class Batteries
    23. {
    24.     public string id;
    25.     public GameObject prefab;
    26. }
    27.  
    28. // Class containing all the motor types
    29. [System.Serializable]
    30. public class Motors
    31. {
    32.     public string id;
    33.     public GameObject prefab;
    34. }
    35.  
    36. // Class containing all the pcb types
    37. [System.Serializable]
    38. public class Pcbs
    39. {
    40.     public string id;
    41.     public GameObject prefab;
    42. }
    43.  
    44. // Class containing all the wheel types
    45. [System.Serializable]
    46. public class Wheels
    47. {
    48.     public string id;
    49.     public GameObject prefab;
    50. }
    51.  
    52. [CreateAssetMenu(fileName = "PartCatalog", menuName = "Catalogs/PartCatalog", order = 0)]
    53. public class PartCatalog : ScriptableObject
    54. {
    55.     public List<Types> types;
    56.     public List<Bodies> bodies;
    57.     public List<Batteries> batteries;
    58.     public List<Motors> motors;
    59.     public List<Pcbs> pcbs;
    60.     public List<Wheels> wheels;
    61.  
    62. }
    I've been filling the scriptable object lists with values, that i want to search through in another script.
    The scriptable object looks like this at the moment.



    I'm new to the subject of reflection, and i think it can help solve my problem, but i'm stuck as to how to do it. I've been searching the forums, but haven't come across an answer yet. Maybe it's not possible at all, but maybe someone can help me point me in the right direction.

    I want to do what's explained in this code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System.Reflection;
    5. using System;
    6.  
    7. public class SerializeRobot : MonoBehaviour
    8. {
    9.     // Set the parts catalog
    10.     public PartCatalog PartCatalog;
    11.  
    12.     // Start is called before the first frame update
    13.     void Start()
    14.     {
    15.         foreach(Types type in PartCatalog.types)
    16.         {
    17.             Debug.Log(type.name);
    18.  
    19.             // Now loop through the scriptable objects class corresponding with the type.name class
    20.             // It works for the class Batteries
    21.             foreach (Batteries battery in PartCatalog.batteries)
    22.             {
    23.                 Debug.Log(battery.prefab.name);
    24.             }
    25.  
    26.             // But instead of Batteries, i want to go through the custom class that we get from type.name
    27.             // I'm stuck here...
    28.             foreach (/* type.name class */ partType in PartCatalog./* type.name class */)
    29.             {
    30.                 Debug.Log(partType.prefab.name);
    31.             }
    32.  
    33.         }
    34.     }
    35. }
    36.  
    I hope this makes sense... Any help is appreciated!
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,893
    You definitely could do this with reflection, that doesn't necessarily mean you should though. What's your end goal here, besides printing out the names of the objects?

    Reflection here would involve calling
    typeof(PartCatalog).GetFields(...)
    to get all the object fields, and then analyzing the generic type of the list so you can call
    thatType.GetField("prefab")
    to get the value of that field... and so on...

    It's really a mess. What is it you are ultimately trying to do? This looks largely like a job for an abstract class or interface at first glance.
     
    padami and lordofduct like this.
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,514
    What are you actually attempting to do? Like what is the goal of this ScriptableObject and what it represents?

    Cause as is, sure, you could use Reflection to get what you want. And I, or many others, could show you how to accomplish it.

    BUT... it's a terrible way to do whatever it is you're attempting to do.

    ...

    So instead... what is it you're attempting to do here?

    What does the 'types' list represent? What would it mean if 'types' only contains "batteries" and "pcbs" and none of the others? What would it mean if it contained "FlarghaBlargha" which doesn't have a corresponding list?

    Why is it that you have a special type for each list despite them being shaped exactly the same?
    {
    string id;
    GameObject prefab;
    }

    Why not use the same type for all lists?

    ...

    Why not do something like this:
    Code (csharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. [System.Serializable]
    7. public class TypeInfo
    8. {
    9.     public string name;
    10.     public List<PrefabInfo> prefabs;
    11. }
    12.  
    13. [System.Serializable]
    14. public class PrefabInfo
    15. {
    16.     public string id;
    17.     public GameObject prefab;
    18. }
    19.  
    20. [CreateAssetMenu(fileName = "PartCatalog", menuName = "Catalogs/PartCatalog", order = 0)]
    21. public class PartCatalog : ScriptableObject
    22. {
    23.     public List<TypeInfo> types;
    24.  
    25. }
    26.  
    And then you could just loop through them:
    Code (csharp):
    1.  
    2. foreach(var type in PartCatalog.types)
    3. {
    4.     Debug.Log(type.name);
    5.     foreach(var info in type.prefabs)
    6.     {
    7.         Debug.Log(info.id);
    8.         Debug.Log(info.prefab.name);
    9.     }
    10. }
    11.  
    (note - this design isn't necessarily the best. But I don't know what you're actually attempting to do. But it's leagues better than using your design and stirring in some reflection.)
     
    padami and PraetorBlue like this.
  4. padami

    padami

    Joined:
    May 19, 2015
    Posts:
    8
    Ok, i was afraid it would be a mess, haha.. thanks for the first input!

    The idea is, i'm fiddling around with some first ideas of making a catalog of parts that can be instantiated. Definately not a final product, and definately a mess, but i'll sketch the goal;

    I have a GameObject with a name, we'll call him bob, and inside that gameobject there are children, which have scripts with types "Motor", "Wheel", "Pcb", which represent different parts of bob. There are multiple prefabs, which are all motor/wheel/pcb, but with different "specifications" and "models".

    I've made a serialization in XML of the different "parts" that are attached to bob, and i want to have a big list of all the parts that CAN be on bob, but not neccessarily HAVE to be on bob. Depending on the data in the XML file, i want to select the corresponding GameObjects from the Scriptable Object that contains all the possible motors/pcb's/wheels/etc.

    Does that make sense?

    I'm kind of prototyping with different kind of ways to accomplish this, and i thought this would be a way to go, but now i'm stuck in "selecting" the right gameobject from the partscatalog. Right now each motor/pcb/wheel has the same variables in it's class, but this will be expanded later.

    Thanks!
     
  5. padami

    padami

    Joined:
    May 19, 2015
    Posts:
    8
    A list with "identifier" name (battery, pcb, wheel, etc), containing a list of each id and prefab, wow that's something that hasn't crossed my mind, that's waaaaaaay easier and gets rid of the need for reflection... Only this won't work if all the PrefabInfo's aren't the same, right? Hmm..
     
  6. padami

    padami

    Joined:
    May 19, 2015
    Posts:
    8
    Now i think of it i could of course just compare the value ID of each part in my XML file to all the parts in the PartsCatalog, that would be fairly easy to get the right data.

    It's making less and less sense now i'm thinking of it again... let's call this a case of tunnle vision and blindly following the wrong path. I have inspiration for less complicated ways of getting the data now with your help :)!