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. Dismiss Notice

How to get item from a dictionary - always returning false

Discussion in 'Scripting' started by TheCelt, Jul 27, 2016.

  1. TheCelt

    TheCelt

    Joined:
    Feb 27, 2013
    Posts:
    718
    Hello

    I have a simple dictionary setup like this:

    Code (CSharp):
    1.  
    2. public Dictionary<string, Weapon> itemDatabase = new Dictionary<string, Weapon>();
    3. itemDatabase.Add("Small Sword", new Sword("Small Sword", 1, 6, 100f)); //sword inherits weapon class
    4.  
    Then in another script i am using this line of code:

    Code (CSharp):
    1.  
    2. public string itemName = "Small Sword";
    3. Weapon t;
    4.  
    5. if (ItemManager.itemDatabase.TryGetValue(itemName, out t))
    6. {
    7.     Sword itemFound = (Sword)t;
    8.     Debug.Log("Found: "+itemFound.name);
    9. }else{
    10.      Debug.Log("Not Found!");
    11. }
    12.  
    Wondering why it always gives not found as a result? What am i getting wrong here?
     
    Last edited: Jul 28, 2016
  2. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Where do you run the code? You've simply copied everything together to post it here so you might wanna provide that information.

    It could be an issue with the execution order, i.e. the second script may try to find the item before the other script adds the item.
    Another reason could be the public string. If you changed it in the inspector, the value in the script would no longer be used but instead, the serialized value would be used.
     
  3. orb

    orb

    Joined:
    Nov 24, 2010
    Posts:
    3,032
    Create in Awake() methods, fetch in Start() or later. That should avoid execution order issues.

    I also think you should look into scriptable objects to make your default item database. Then you just add the items in the inspector and it saves automatically.
     
  4. TheCelt

    TheCelt

    Joined:
    Feb 27, 2013
    Posts:
    718
    @orb i hate using the inspector, prefer to link it all via code.

    I am creating it in Awake and fetching in Start.

    It seems i can find the key if i use ContainsKey in the script i created it in.
    But if i use the same in another script not only does it not find the key, it then cannot find the key in the original creation script. So i seem to be losing the data like it erases it.

    If i comment out the code in the script that fetches it - then i can once again find the key in the dictionary in in the script that created it. So that code seems to be removing it from the dictionary for some reason.
     
  5. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    Can you post the complete code? If it's too long, remove some parts but don't remove the methods in which you run the code.
     
  6. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,139
    Your dictionary is <string, Weapon> but your variable is Weapons t. Is this a typo?
     
  7. TheCelt

    TheCelt

    Joined:
    Feb 27, 2013
    Posts:
    718
    Sure here is the creation of dictionary:

    Code (csharp):
    1.  
    2. //script class name is DatabaseHandler
    3. public Dictionary<string, Weapon> itemDatabase = new Dictionary<string, Weapon>();
    4.     void Awake()
    5.     {
    6.         itemDatabase.Add("Small Sword", new Sword("Small Sword", 1, 6, 100f));
    7.     }
    8.  
    The look up script:
    Code (csharp):
    1.  
    2. DatabaseHandler ItemManager;
    3. public string componentName = "Small Sword";
    4. Sword sword;
    5.  
    6. void Start(){
    7.    ItemManager = GameObject.Find("Main").GetComponent<DatabaseHandler>();
    8.    Debug.Log(ItemManager); //check to see if null
    9.    if (ItemManager.itemDatabase.ContainsKey(componentName)) {
    10.           Debug.Log("Contains: Key Found");
    11.    } else {
    12.           Debug.Log("Contains: Key not found!");
    13.    }
    14.  
    15.    Weapon t;
    16.         if (ItemManager.itemDatabase.TryGetValue(componentName, out t))
    17.         {
    18.               sword = (Sword)t;
    19.         }
    20.         else
    21.         {
    22.              Debug.Log("No Sword found!");
    23.         }
    24. }
    25.  
    So as you can probably guess, i get "Contains: Key not found!", and "No Sword Found!" as a result.
     
    Last edited: Jul 28, 2016
  8. Polymorphik

    Polymorphik

    Joined:
    Jul 25, 2014
    Posts:
    599
    Add a Debug.Log("Added item") in the awake function to see if tis getting stored. I think the GameObject might be disabled or something else is going on.
     
  9. TheCelt

    TheCelt

    Joined:
    Feb 27, 2013
    Posts:
    718
    I solved it - turns out unity inspector for string componentName had a different value to what i hard written so it was replacing it with the inspector value which is freaking stupid if you ask me specially without logging the fact that the inspector overwrote the value to make life easier of knowing whats going on.
     
  10. orb

    orb

    Joined:
    Nov 24, 2010
    Posts:
    3,032
    That would be what @Suddoha suggested then - if you change it in the inspector it gets serialised. It's core functionality in Unity.
     
  11. TheCelt

    TheCelt

    Joined:
    Feb 27, 2013
    Posts:
    718
    How else do you give each prefab a unique name string without the inspector given i can't hard code it in the script as they would all end up with the same name?
     
  12. Polymorphik

    Polymorphik

    Joined:
    Jul 25, 2014
    Posts:
    599
    I still don't see a problem...I'm not sure what it is you are trying to do now. You create a string variable and assign it in Unity that's the Unique ID, whats the problem? I think your method of storing the diction may be off. Again I have no idea what you are trying to accomplish but Unity is doing that you tell it do so...
     
  13. TheCelt

    TheCelt

    Joined:
    Feb 27, 2013
    Posts:
    718
    I am basically trying to create a dictionary list of all my items which will store things like their price for example to buy. So when the object instantiates, it can find its data via the dictionary look up. At least i presume thats how people do it.
     
  14. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    You can do it the way you want to.
    The only problem that occured here is that you've added the item as 'Small Sword' within one script and (like you said) the value in the inspector was different.
    With that approach you have to make sure they match.


    That's exactly the feature which easily allows you do assign different values to different instances of a script.

    However, there are other approaches which are probably better as it's usually bad practice to clutter the code with actual data, simply because data is often subject to change.
    For instance, have a look at ScriptableObjects (SOs), like @orb suggested. You could make an item database with those and then link the SO in the inspector. That allows you to have a single source for the data and SOs are also not bound to a specific object or scene. They're kind of data assets, pretty handy and they can save a lot of time.