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

How to couple a Type with a GameObject?

Discussion in 'Scripting' started by MaskedMouse, Oct 25, 2019.

  1. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    1,064
    I'm kind of searching for a way to couple a specific class with a prefab.
    So basically
    Dict<Type, GameObject>
    . Where in the editor I can select the Type and then tie a prefab to that Type. To then instantiate that prefab whenever I go through the list.
    I know that Unity's serialization restriction is preventing
    Dict<T, T>
    from being serialized. Though with some extension it can be made serializable.

    Use case:
    I've got a
    List<BaseClass>
    BaseClass is abstract and is always inherited.

    When I want to instantiate prefabs that belong to that
    ClassA
    I'd have to serialize the prefab and use a Switch case to handle
    case ClassA classA:
    and then instantiate the right prefab.

    Instead what I want to do is instantiate it through the type, like
    Instantiate(TypeDict[class.GetType()]);
    it would save me a lot of changing code constantly when a new type is introduced and always instantiates a gameobject that belongs to the type.

    But the question is how to achieve a serializable dictionary
    Dict<Type,GameObject>
    where
    Type
    is restricted to anything that inherits from
    BaseClass

    That way I can simply serialize a prefab to that type and don't have to add more switch cases.
     
  2. Sebastian1989101

    Sebastian1989101

    Joined:
    Sep 5, 2017
    Posts:
    12
    You can use a serializeable struct that holds the type of your class and the prefab from the game object. This struct than can be used as array or list within your hosting object. To accessing it you can use linq queries like first.

    Code from Notepad++ scratch (not tested) and would require the System.Linq namespace:

    Code (CSharp):
    1. [Serializable]
    2. public struct Container
    3. {
    4.     public Type ClassType { get; set; }
    5.     public GameObject Prefab { get; set; }
    6. }
    7.  
    8. public Container[] containers;
    9.  
    10. var prefab = containers.First(c => c.ClassType == class.GetType())?.Select(c => c.Prefab);
    If you want to access it with the indexer you can create a custom list type for it. See: https://docs.microsoft.com/dotnet/csharp/programming-guide/indexers/
     
  3. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    1,064
    This won't serialize in the editor because System.Type is not serializable by default.
    Also properties are not serializable either.
     
  4. Sebastian1989101

    Sebastian1989101

    Joined:
    Sep 5, 2017
    Posts:
    12
    nvm just read your post a 2nd time. This would require another solution. In the case to make sure that Type inherited from BaseClass you might want to consider using generics.

    Or a more hacky approche like this one:

    Code (CSharp):
    1. var prefab = containers.First(c => c.ClassType == myclass.GetType() && c.ClassType.BaseType == typeof(BaseClass)).Prefab;
     
  5. Sebastian1989101

    Sebastian1989101

    Joined:
    Sep 5, 2017
    Posts:
    12
    You can also use a string that represents the type. It would just change the linq query a bit (but it is risky on renaming). Properties on the other hand are serializeable on C# standards, not sure about Unity because I'm new in the Unity world.
     
  6. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    1,064
    Yeah Unity's serialization system is quite limited.
    The only way to get properties serialized is using [field: Serializable] as attribute. And even then it looks ugly in the inspector. The property must have a getter and a setter defined as well. So even more limitations.

    System.Type is not serializable. But you can make it serializable by a custom serialization script / custom property drawer. Just forgot how.

    Odin could probably serialize it but I only use it at home and not at work.
     
    Last edited: Oct 25, 2019
  7. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    1,064
    I guess as a workaround I'll just generate
    ScriptableObject
    's after the compiler reloads the scripts. So that they represent the type and hang a
    AssetReferenceGameObject 
    to it or
    GameObject
    .
    Then just compare the type name at runtime using
    GetType().Name