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
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

[Resolved] Dictionary as Item Database

Discussion in 'Scripting' started by Shnok, Aug 14, 2015.

  1. Shnok

    Shnok

    Joined:
    Aug 14, 2015
    Posts:
    4
    Hi, i want to use a dictionary as an item database for my game. I could use a monobehaviour and put the script on every objects that needs to use the itemData but i dont really want to do it so:

    I use a custom class called ItemData with a dictionary of string as key and Item as type.

    I want to add keys at startup and i dont really know how to do it. Well, you'll see in my script.

    Unity doesnt react really bad, i get no error.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Networking;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6.  
    7. [System.Serializable]
    8. public class Item
    9. {
    10.     public enum ItemType{Sword,Shield,Consumable,Misc};
    11.     public int ID;
    12.     public string Name;
    13.     public Texture2D Icon;
    14.     public ItemType Type;
    15.     public GameObject StaticMesh;
    16.     public AudioClip DropSound;
    17. }
    18.  
    19. public class ItemData{
    20.    
    21.     public static Dictionary<string, Item> items;
    22.  
    23.     public static Dictionary<string, Item> Items {
    24.         get {
    25.             if (items == null)
    26.             {
    27.                 LoadItemsData();
    28.             }
    29.             return items;
    30.         }
    31.     }
    32.  
    33.     public static void LoadItemsData(){
    34.         items = new Dictionary<string, Item>();
    35.  
    36.         Item newItem = new Item(){
    37.             ID=0,
    38.             Name="Money",
    39.             Icon=null,
    40.             Type=Item.ItemType.Misc,
    41.             StaticMesh=Resources.Load("Data/Items/Money",typeof(GameObject)) as GameObject,
    42.             DropSound=Resources.Load("Data/Items/MoneySound",typeof(AudioClip)) as AudioClip
    43.         };
    44.        
    45.         items.Add (newItem.Name,newItem);
    46.  
    47.         newItem = new Item(){
    48.             ID=1,
    49.             Name="Coin",
    50.             Icon=null,
    51.             Type=Item.ItemType.Misc,
    52.             StaticMesh=Resources.Load("Data/Items/Coin",typeof(GameObject)) as GameObject,
    53.             DropSound=Resources.Load("Data/Items/MoneySound",typeof(AudioClip)) as AudioClip
    54.         };
    55.        
    56.         items.Add (newItem.Name,newItem);
    57.     }
    58.    
    59.     public static Item GetItem(string name){
    60.         Item temp = null;
    61.         if(items.TryGetValue(name,out temp)){
    62.             return temp;
    63.         }else return null;
    64.     }
    65.    
    66. }
    67.  
    I get a NullReferenceException: Object reference not set to an instance of an object on my line
    Code (CSharp):
    1. if(items.TryGetValue(name,out temp)){
    when i call the method "GetItem". So my dictionary doesnt seem to be created.

    If you have any idea, thanks :)
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    You don't instantiate 'items' until someone access 'Items' (note the case of the letter i there).

    Thing is in your 'GetItem' method you access 'items', not 'Items'. So... you never actually access 'Items', and subsequently you never instantiate 'items'. 'items' is therefore null when you say 'items.TryGetValue', resulting in your null reference exception.

    Try calling 'items' something else... when I have a similar design I usually call the dictionary '_lookupTable' or '_table' or in this case... '_itemsTable'. It'll make your code a little more readable maybe.

    Oh... and the 'items' table, you should probably make it private, encapsulate it. Otherwise any other class can access and modify it.
     
    Kiwasi likes this.
  3. makeshiftwings

    makeshiftwings

    Joined:
    May 28, 2011
    Posts:
    3,350
    I think you want "Items.TryGetValue" (capital I) not "items.TryGetValue".
     
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    Honestly... here's how I probably would have done it.

    Encapsulate, reduce necessity to test if the dictionary is null, give an interface to do what would have originally been possible... but due to not uncovering the underlying dictionary, we can easily swap out the actual data structure down the line if dictionary proves inefficient.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Networking;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6.  
    7.  
    8. [System.Serializable]
    9. public class Item
    10. {
    11.  
    12.     public enum ItemType{Sword,Shield,Consumable,Misc};
    13.     public int ID;
    14.     public string Name;
    15.     public Texture2D Icon;
    16.     public ItemType Type;
    17.     public GameObject StaticMesh;
    18.     public AudioClip DropSound;
    19.    
    20. }
    21.  
    22. public class ItemData
    23. {
    24.    
    25.     private static Dictionary<string, Item> _table;
    26.  
    27.     //instead use the static constructor to instante _table,
    28.     //since _table is necessary to the operation of this class
    29.     //why waste cycles testing null on every access of it???
    30.     static ItemData()
    31.     {
    32.         _table = new Dictionary<string, Item>();
    33.  
    34.         Item newItem = new Item()
    35.         {
    36.             ID=0,
    37.             Name="Money",
    38.             Icon=null,
    39.             Type=Item.ItemType.Misc,
    40.             StaticMesh=Resources.Load("Data/Items/Money",typeof(GameObject)) as GameObject,
    41.             DropSound=Resources.Load("Data/Items/MoneySound",typeof(AudioClip)) as AudioClip
    42.         };
    43.        
    44.         _table.Add (newItem.Name,newItem);
    45.  
    46.         newItem = new Item()
    47.         {
    48.             ID=1,
    49.             Name="Coin",
    50.             Icon=null,
    51.             Type=Item.ItemType.Misc,
    52.             StaticMesh=Resources.Load("Data/Items/Coin",typeof(GameObject)) as GameObject,
    53.             DropSound=Resources.Load("Data/Items/MoneySound",typeof(AudioClip)) as AudioClip
    54.         };
    55.        
    56.         _table.Add (newItem.Name,newItem);
    57.     }
    58.    
    59.     public static Item GetItem(string name)
    60.     {
    61.         Item temp = null;
    62.         if(_table.TryGetValue(name,out temp){
    63.             return temp;
    64.         else
    65.             return null;
    66.     }
    67.    
    68.     //Seeing as you had the Items Dictionary public, I couldn't see why, unless you wanted to allow other objects to add items to the database... so add methods to do so
    69.     public static void AddItem(Item item)
    70.     {
    71.         _table[item.Name] = item;
    72.     }
    73.    
    74.     public static bool RemoveItem(string name)
    75.     {
    76.         return _table.Remove(name);
    77.     }
    78.    
    79. }
    80.  
     
    Kiwasi likes this.
  5. Shnok

    Shnok

    Joined:
    Aug 14, 2015
    Posts:
    4
    Wow, thanks ! :) I shoul look more closer to the fundamentals. I always try to avoid what i dont know. Thank you for the enlightenment ! And for the 'public' to be honest, i didnt know.

    Thanks !
     
    Kiwasi likes this.