Search Unity

ScriptableObject instances issue with duplicates and prefabs of GameObject

Discussion in 'Scripting' started by nicmarxp, Apr 19, 2019.

  1. nicmarxp

    nicmarxp

    Joined:
    Dec 3, 2017
    Posts:
    406
    Hey guys!

    I have an Interaction script on a door, with a list of reactions, where I can add reactions that are stored as scriptable objects, that derive from a BaseReaction ScriptableObject I made. Here I can for example assign a transform with the door sprite, that will move when I press a button. That all works fine. But there are two major issues:

    1) If I duplicate this object, the first door is still assigned to the reaction. If I change this to the new door, it changes the first door too, so it seems like the duplication has the exact same scriptable object instance.

    2) If I create a prefab of the door, and then insert it, the scriptable object is empty. The reaction list contains 1 item, but it's empty.

    I need to be able to duplicate and prefab things when building levels, or else I would have to create each door reactions manually each time.

    Is there a solution to this, to make data stored inside gameobjects be unique and permanent, so I can both duplicate and prefab them, to retain all data?

    Should I maybe use regular objects/classes instead, or will that give the same issue?

    Thank you in advance!

     
  2. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,690
    Is the reaction an instance or a reference to a ScriptableObject asset?

    Ultimately you may find it easier to use MonoBehaviours for reactions. Maintaining, cloning, destroying, etc., ScriptableObject instances that are nested inside other UnityEngine.Objects can be a headache.
     
  3. nicmarxp

    nicmarxp

    Joined:
    Dec 3, 2017
    Posts:
    406
    Hi Tony! Thanks for the reply!

    I am using instances of the SO, but (logically) it just duplicates the reference.

    As you might have noticed from the screenshots, I'm using Odin, which is great to make an editor, but I haven't figured out how to solve this yet.

    I tried to do the same thing with a regular class, but I get these errors in the Serialization Debugger of Odin:
    - The public field defaultReaction2 is skipped by Unity because Unity does not support the type List<BaseReaction2>
    - The type List<BaseReaction2> is not supported by Unity because Unity does not support the element type of BaseReaction2.

    I have a List (defaultReaction2) of my custom type (BaseReaction2), which now is a class, instead of a scriptable object, to see if this makes any difference, but I can't get it serialized.

    I also tried making it a monobehaviour, but I guess I can't attach that as an item to a list, and edit its contents in the inspector.

    I need reactions to be multiple scripts (like TextReaction) that derive from BaseReaction.

    Then I attach different combinations of those based on different conditions.

    I can’t figure out how to do this with MonoBehaviours and have them nested and editable inside a list in the inspector.
     
  4. nicmarxp

    nicmarxp

    Joined:
    Dec 3, 2017
    Posts:
    406
    I just realized that the example i based this on (https://unity3d.com/learn/tutorials/projects/adventure-game-tutorial) had a GameObject for each Reaction, that contained the different reactions, and in the Interactable, you assign these based on different conditions.

    So I guess this would be a way to use MonoBehaviours.

    I just find it nice to have it all in one editor/inspector, instead of having to create Reactions and Conditions in a different gameobject, and jump back and forth.

    But perhaps (probably) there is a way to way a custom inspector to handle it all inside one window, and behind the scenes, it creates the appropriate gameobjects and reactions/conditions.

    If there was a way to make this with Odin, instead of a custom editor, it would be a lot faster... hmm.. @TonyLi is this what you meant, or could you suggest another solution?

    Thanks!
     
  5. TonyLi

    TonyLi

    Joined:
    Apr 10, 2012
    Posts:
    12,690
    If you don't mind not using Odin for this, you can write a custom inspector. The ability system in Opsive's character controllers is a good example. Each ability is a separate MonoBehaviour, but their inspectors are drawn in the main MonoBehaviour:

    upload_2019-4-20_8-55-34.png

    You can do the same with ScriptableObjects, like in Quest Machine:

    upload_2019-4-20_9-1-14.png

    But then you have to keep track of instantiating, destroying, and cloning them. When you use MonoBehaviours, Unity takes care of that for you.

    To show an editor inside another editor, use Editor.CreateEditor to create the reaction's editor:

    Code (csharp):
    1. reactionEditor = Editor.CreateEditor(reaction);
    In the Interaction's custom editor, call the reaction editor's OnInspectorGUI() method:

    Code (csharp):
    1. [CustomEditor(typeof(Interaction))] public class InteractionEditor : Editor
    2. {
    3. ...
    4.     public override void OnInspectorGUI()
    5.     {
    6.         ...
    7.         reactionEditor.OnInspectorGUI();
     
  6. nicmarxp

    nicmarxp

    Joined:
    Dec 3, 2017
    Posts:
    406
    Oh very cool! I will definitely try this out! I got so obsessed over SO’s so I wanted to use them for everything but this seems ideal for prefabing and duplicating gameobjects.

    Thank you! :)