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

Instance of Scriptableobject inside a Scriptableobject

Discussion in 'Scripting' started by iProge, Dec 19, 2019.

  1. iProge

    iProge

    Joined:
    Dec 19, 2019
    Posts:
    4
    Hello,

    I think i hit the brickwall on my item/character system design.

    I was going to use Scriptableobjects as a template and then just create instance of it when i need a new item. It was working fine inside a scene when i tested it but when i implemented scriptableobject inventory system i soon noticed that it wasn't going to work at all.

    So here is how i was planning it to work:
    • Create new item scriptableobject asset ex. "Sword"

    • Scene will have Item Creation script that have reference to "Sword"

    • Item Creation makes new instance of "Sword" via CreateInstance()

    • Modify new "Sword" item etc.

    • Add "Sword" to list inside a Inventory scriptableobject
    But when i do it this way inventory only gets "Type mismatch".

    Having a hunch why this is happening, but not 100% sure because i thought scriptableobjects were different then normal objects created inside a scene.

    On a workaround i made a serializable item class that holds an item scriptableobject with basic variables, but making it this way feels very clunky and i need to make loads of classes and inheritance to make it flexible system.

    So what i'm asking is...
    • Is there something i'm missing here why it won't work as intended?

    • Why im getting "Type mismatch" between two scriptableobjects?

    • Is there a better way of doing it?

    • If not, is the serializable item class my only option?
    I really hope i can get some insight from you and the brickwall is just my lack of knowledge.

    Thanks

    - Proge
     
    Last edited: Dec 19, 2019
  2. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,204
    What do you mean by "you get type missmatch"?
     
  3. iProge

    iProge

    Joined:
    Dec 19, 2019
    Posts:
    4
    Here is simple version what i mean:

    Code (CSharp):
    1. [CreateAssetMenu]
    2. public class Item : ScriptableObject
    3. {
    4.     public string itemName;
    5. }
    Code (CSharp):
    1. [CreateAssetMenu]
    2. public class Inventory : ScriptableObject
    3. {
    4.     public List<Item> itemInventory = new List<Item>();
    5. }
    Code (CSharp):
    1. public class ItemCreation : MonoBehaviour
    2. {
    3.     public Inventory inventory;
    4.     public Item itemData;
    5.  
    6.     private Item newItem;
    7.  
    8.     public void NewItem()
    9.     {
    10.         newItem = ScriptableObject.CreateInstance<Item>();
    11.         newItem.itemName = "Sword";
    12.     }
    13.  
    14.     private void Start()
    15.     {
    16.         NewItem();
    17.  
    18.         inventory.itemInventory.Add(newItem);
    19.     }
    20. }
    And outcome looks like this:

    unity_scriptableobject_typemismatch0001.png
     
  4. iProge

    iProge

    Joined:
    Dec 19, 2019
    Posts:
    4
    Same thing happens if i use Instantiate()

    Code (CSharp):
    1. public class ItemCreation : MonoBehaviour
    2. {
    3.     public Inventory inventory;
    4.     public Item itemData;
    5.  
    6.     private Item newItem;
    7.  
    8.     public void NewItem()
    9.     {
    10.         newItem = Instantiate(itemData);
    11.         newItem.itemName = "Sword";
    12.     }
    13.  
    14.     private void Start()
    15.     {
    16.         NewItem();
    17.  
    18.         inventory.itemInventory.Add(newItem);
    19.     }
    20. }
     
  5. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    Hi @unity_ZYRIY44eBE0BHg

    You are trying to add a runtime created ScriptableObject that hasn't got an asset file to your ScriptableObject asset (= inventory).

    You can't cross that boundary (scene object ref in asset file) that is why you get the type mismatch error - AFAIK.

    Either;
    1. Create an asset file for each item and and add them to your inventory in asset file.

    2. Place the inventory in your MonoBehaviour or in some serializable class inside MB and add runtime instanced ScriptableObjects to its list.

    This would work:
    Code (CSharp):
    1. public class ItemCreation : MonoBehaviour
    2. {
    3.     public Item itemData;
    4.     public Inventory inventory; // runtime inventory
    5.  
    6.     void Start()
    7.     {
    8.         AddNewItem();
    9.     }
    10.  
    11.     public void AddNewItem()
    12.     {
    13.         var newItem = ScriptableObject.CreateInstance<Item>();
    14.         newItem.itemName = "Sword";
    15.         inventory.itemInventory.Add(newItem);
    16.     }
    17. }
    18.  
    19. [System.Serializable]
    20. public class Inventory
    21. {
    22.     public List<Item> itemInventory = new List<Item>();
    23. }
     
  6. iProge

    iProge

    Joined:
    Dec 19, 2019
    Posts:
    4
    Thanks for answer and sorry for late reply, damn holidays

    Sad to hear that scriptableobjects limit comes when you need to make dynamic items at my case atleast, love them otherwise and was hoping to use them as much as possible instead of singletons but this time it looks like i have to make exception.

    Going to need my inventory on multiple scenes, so singleton might be my only real option?

    This is what i came up:

    Code (CSharp):
    1. public class InventoryManager : MonoBehaviour
    2. {
    3.     public static InventoryManager Instance;
    4.  
    5.     public List<Inventory> inventoryContainer = new List<Inventory>();
    6.  
    7.     public Inventory currentInventory;
    8.  
    9.     private void Awake()
    10.     {
    11.         if (Instance == null)
    12.         {
    13.             DontDestroyOnLoad(gameObject);
    14.             Instance = this;
    15.         }
    16.  
    17.         else if (Instance != this)
    18.         {
    19.             Destroy(gameObject);
    20.         }
    21.     }
    22.  
    23.     public void GetInventory(int id)
    24.     {
    25.         foreach (var inventory in inventoryContainer)
    26.         {
    27.             if (inventory.id == id)
    28.             {
    29.                 currentInventory = inventory;
    30.             }
    31.         }
    32.     }
    33. }
    Code (CSharp):
    1. [System.Serializable]
    2. public class Inventory
    3. {
    4.     public int id;
    5.     public int inventorySize;
    6.  
    7.     public List<Item> inventory = new List<Item>();
    8.     public List<Item> equipement = new List<Item>();
    9.  
    10.  
    11.     public void AddItem(Item item)
    12.     {
    13.         inventory.Add(item);
    14.     }
    15.  
    16.     public void RemoveItem(Item item)
    17.     {
    18.         inventory.Remove(item);
    19.     }
    20.  
    21.     public void EquipItem(Item item)
    22.     {
    23.  
    24.     }
    25.  
    26.     public void UnequipItem(Item item)
    27.     {
    28.  
    29.     }
    30. }
    Code (CSharp):
    1. public class ItemCreation : MonoBehaviour
    2. {
    3.     public Item itemData;
    4.  
    5.     public void NewItem(string name)
    6.     {
    7.         Item newItem = Instantiate(itemData);
    8.         newItem.itemName = name;
    9.         newItem.name = name;
    10.         InventoryManager.Instance.currentInventory.AddItem(newItem);
    11.     }
    12.  
    13.     private void Start()
    14.     {
    15.         NewItem("Sword");
    16.         NewItem("Mace");
    17.         NewItem("Axe");
    18.     }
    19. }
    Each different player character have unique "id" and InventoryManager uses that "id" to fetch current characters inventory
     
  7. PN3D

    PN3D

    Joined:
    Jul 12, 2013
    Posts:
    6
    You have to use:

    var parentScriptableObject= ScriptableObject.CreateInstance< YourParentSO >();
    AssetDatabase.CreateAsset( parentScriptableObject, "Assets/Parent.asset" );
    var nestedScriptableObject = ScriptableObject.CreateInstance< YourNestedSO >();
    nestedScriptableObject.name = "Some Nested SO";
    AssetDatabase.AddObjectToAsset( nestedScriptableObject, parentScriptableObject );
    EditorUtility.SetDirty( parentScriptableObject );
    AssetDatabase.SaveAssets();
     
    Last edited: May 24, 2023