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 manage ScriptableObjects ?

Discussion in 'Scripting' started by BIOoOAG, Jun 2, 2020.

  1. BIOoOAG

    BIOoOAG

    Joined:
    May 14, 2020
    Posts:
    6
    Hello Unity community!
    2 questions:

    I try to use correctly scriptables objects, but I not really sure about how to manage them.
    • Do I have to store them (after a initiate) in a GameObject Array, List, other?

    And for exemple, I made a cards game, when i use a cards (drop it on an enemy).
    • What the best way to retrieve variables and fonctions of this specific card in the array with all my scriptables cards?


    Thanks!
     
  2. Ardenian

    Ardenian

    Joined:
    Dec 7, 2016
    Posts:
    313
    An instance of a
    ScriptableObject
    definition is data that you can reference everywhere. In your case, such an instance could represent a card in your game. How you organize these instances, that is up to you and your need in the game.

    What you could do, for example, is creating a SO instance for every card in your game and if the player has a collection of cards, appropriately reference them there. Note that SO instances alone usually do not solve everything, often you need wrappers. If a player has collected a card, for instance, such a simple wrapper could look like this:
    Code (CSharp):
    1. public class CardCollection : MonoBehaviour {
    2.  
    3.     [Serializable]
    4.     public class CollectedCard {
    5.         public Card instance; // Card : ScriptableObject
    6.         public int amount;
    7.     }
    8.  
    9.     [SerializeField]
    10.     private CollectedCard[] collected;
    11. }
    In other words, ScriptableObjects are a good start, but you will usually need to build around them, not just with a simple list or array, but complex structures, containers and wrappers.
     
    BIOoOAG likes this.
  3. BIOoOAG

    BIOoOAG

    Joined:
    May 14, 2020
    Posts:
    6
    Really interesting, it also could use for a deck. I will try to use this for now and come back later if I have question.

    thanks for yours tips!
     
  4. BIOoOAG

    BIOoOAG

    Joined:
    May 14, 2020
    Posts:
    6
    Hello again,

    I not really sure about how to find and add my SO in my class.
    Now I have 1 prefab (a card) and several SO that change attribute of my card.

    Edit: I make a struct that store all my cards generated:
    - When I use Class rather than Struct it doesn´t work, i don´t know why? -> "NullReferenceException: Object reference not set to an instance of an object" on these lines:
    • playerDeck.Cards = initCard;
      [*]playerDeck.amount = 1;

    any idea?

    - Is it a good start? What can I improve?

    Code (CSharp):
    1. public class Deck : MonoBehaviour
    2. {
    3.     [Serializable]
    4.     public struct PlayerDeck
    5.     {
    6.         public GameObject Cards; // Card : ScriptableObject
    7.         public int amount;
    8.     }
    9.  
    10.     public PlayerDeck[] playerDeck;
    11.  
    12.  
    13.     /***** Prefab card *****/
    14.     public GameObject prefabCard;
    15.     public SoCards[] tmpSoCards;
    16.     public string[] results;
    17.     public GameObject initCard;
    18.  
    19.     /***** Parent *****/
    20.     public GameObject cardsList;
    21.  
    22.     public void Start()
    23.     {
    24.         prefabCard = GameObject.FindGameObjectWithTag("Prefab Card");
    25.         cardsList = GameObject.FindGameObjectWithTag("Cards List"); // Game object that will contain all Cards (Game object)
    26.  
    27.  
    28.         /***** Init Deck *****/
    29.         results = AssetDatabase.FindAssets("t:SoCards"); // Path of cards SO
    30.         tmpSoCards = new SoCards[results.Length]; //store the path
    31.         playerDeck = new PlayerDeck[results.Length]; //Struct with all cards
    32.  
    33.         for (int i = 0; i < results.Length; i++)
    34.         {
    35.             tmpSoCards[i] = (SoCards)AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(results[i]), typeof(SoCards));
    36.  
    37.             initCard = Instantiate(prefabCard);
    38.             initCard.transform.SetParent(cardsList.transform);
    39.             initCard.name = AssetDatabase.GUIDToAssetPath(results[i]);
    40.             initCard.GetComponentInChildren<CardsEffects>().data = tmpSoCards[i];
    41.             initCard.SetActive(false);
    42.            
    43.             playerDeck[i].Cards = initCard;
    44.             playerDeck[i].amount = 1;
    45.         }
    46.     }
    47. }
     
    Last edited: Jun 4, 2020
  5. Ardenian

    Ardenian

    Joined:
    Dec 7, 2016
    Posts:
    313
    A class reference can either reference an instanced object or nothing, whereas a struct always references an instanced object. In other words, if you have a class reference, you have to assign an instanced object to it before using it while when using a struct, you get the default object of that struct type.

    To use it as a class, add this to your code:
    Code (CSharp):
    1.  
    2.         playerDeck = new PlayerDeck[results.Length]
    3.         for(int someIndex = 0; someIndex < playerDeck; someIndex++){
    4.             playerDeck[someIndex] = new PlayerDeck();
    5.         }
    6.  
     
    BIOoOAG likes this.