Search Unity

Null Reference Exception

Discussion in 'Scripting' started by Addison1011, Feb 7, 2017.

  1. Addison1011

    Addison1011

    Joined:
    Dec 15, 2016
    Posts:
    8
    I have been trying to tackle this error for a few hours now and I just cant seem to find the problem.

    The Error:
    NullReferenceException: Object reference not set to an instance of an object
    Inventory.AddItem () (at Assets/Scripts/Inventory.cs:48)
    Inventory.Start () (at Assets/Scripts/Inventory.cs:33)

    The line of code apparently responsible for the error is

    Code (csharp):
    1.  
    2. itemObj.GetComponent<Image>().sprite = itemToAdd.Sprite;
    3.  
    For more clarity the line of code responsible for the error is contained in a method i made called AddItem.
    The Null Reference Exception is only thrown when I try to call the AddItem method in the start method.

    Here is the code for the Inventory Class:


    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.UI;
    5.  
    6. public class Inventory : MonoBehaviour
    7. {
    8.     ItemDatabase database;
    9.     GameObject inventoryPanel;
    10.     GameObject slotPanel;
    11.     public GameObject inventorySlot;
    12.     public GameObject inventoryItem;
    13.  
    14.     int slotAmount;
    15.     public List<Item> items = new List<Item>();
    16.     public List<GameObject> slots = new List<GameObject>();
    17.  
    18.     private void Start()
    19.     {
    20.         database = GetComponent<ItemDatabase>();
    21.  
    22.         slotAmount = 16;
    23.         inventoryPanel = GameObject.Find("Inventory Panel");
    24.         slotPanel = inventoryPanel.transform.FindChild("Slot Panel").gameObject;
    25.  
    26.         for (int i = 0; i < slotAmount; i++)
    27.         {
    28.             items.Add(new Item());
    29.             slots.Add(Instantiate(inventorySlot));
    30.             slots[i].transform.SetParent(slotPanel.transform);
    31.         }
    32.  
    33.         AddItem(0);
    34.  
    35.     }
    36.  
    37.     public void AddItem(int id)
    38.     {
    39.         Item itemToAdd = database.FetchItemByID(id);
    40.  
    41.         for(int i = 0; i < items.Count; i += 1)
    42.         {
    43.             if(items[i].ID == -1)
    44.             {
    45.                 items[i] = itemToAdd;
    46.                 GameObject itemObj = Instantiate(inventoryItem);
    47.                 itemObj.transform.SetParent(slots[i].transform);
    48.                 itemObj.GetComponent<Image>().sprite = itemToAdd.Sprite;
    49.                 itemObj.transform.position = Vector2.zero;
    50.                 return;
    51.  
    52.             }
    53.         }
    54.     }
    55. }


    Then the methods called in this script are from another script called ItemDatabase.
    Here is the ItemDatabase Script:



    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using LitJson;
    5. using System.IO;
    6.  
    7. public class ItemDatabase : MonoBehaviour
    8. {
    9.     private List<Item> database = new List<Item>();
    10.     private JsonData itemData;
    11.  
    12.     private void Start()
    13.     {
    14.         itemData = JsonMapper.ToObject(File.ReadAllText(Application.dataPath + "/StreamingAssets/Items.json"));
    15.         ConstructItemDatabase();
    16.     }
    17.  
    18.     public Item FetchItemByID(int id)
    19.     {
    20.         for (int i = 0; i < database.Count; i++)
    21.         {
    22.             if (database.ID == id)
    23.             {
    24.                 return database; // returns item of index i, which is of type Item
    25.             }
    26.         }
    27.         return null;
    28.     }
    29.  
    30.     void ConstructItemDatabase()
    31.     {
    32.  
    33.         for(int i = 0; i < database.Count; i++)
    34.         {
    35.             database.Add(new Item((int)itemData["id"], itemData["title"].ToString(), (int)itemData["value"],
    36.                 (int)itemData["stats"]["power"], (int)itemData["stats"]["defence"], (int)itemData["stats"]["vitality"],
    37.                 itemData["description"].ToString(), (bool)itemData["stackable"], (int)itemData["rarity"], itemData["slug"].ToString()));
    38.         }
    39.  
    40.     }
    41. }
    42.  
    43. public class Item
    44. {
    45.     public int ID { get; set; }
    46.     public string Title { get; set; }
    47.     public int Value { get; set; }
    48.     public int Power { get; set; }
    49.     public int Defence { get; set; }
    50.     public int Vitality { get; set; }
    51.     public string Description { get; set; }
    52.     public bool Stackable { get; set; }
    53.     public int Rarity { get; set; }
    54.     public string Slug { get; set; }
    55.     public Sprite Sprite { get; set; }
    56.  
    57.     public Item(int id, string title, int value, int power, int defence, int vitality, string description, bool stackable, int rarity, string slug)
    58.     {
    59.         this.ID = id;
    60.         this.Title = title;
    61.         this.Value = value;
    62.         this.Power = value;
    63.         this.Vitality = vitality;
    64.         this.Description = description;
    65.         this.Stackable = stackable;
    66.         this.Rarity = rarity;
    67.         this.Slug = slug;
    68.         Sprite = Resources.Load("Sprites/PNG/" + slug) as Sprite;
    69.  
    70.     }
    71.     public Item()
    72.     {
    73.         this.ID = -1;
    74.     }
    75. }


    I Appreciate any help I can get.
    Thank you.
     
    Last edited: Feb 7, 2017
  2. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
  3. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    Your error is probably items = itemToAdd - one Start is probably being called later than the other Start and your ItemDatabase isn't properly initialized.
     
  4. Timelog

    Timelog

    Joined:
    Nov 22, 2014
    Posts:
    528
    First and foremost, please do what @LeftyRighty said and format your post normally, it's pretty hard to read currently.

    That said, you should really get an error in you FetchItemByID method from the ItemDatabase, as it shouldn't compile as is:

    Code (CSharp):
    1. public Item FetchItemByID(int id)
    2. {
    3.     for (int i = 0; i < database.Count; i++)
    4.     {
    5.         if (database.ID == id) // This shouldn't compile!!!!!
    6.         {
    7.             return database; // returns item of index i, which is of type Item
    8.         }
    9.     }
    10.    
    11.     return null;
    12. }
    Just change that code to:
    Code (CSharp):
    1. public Item FetchItemByID(int id)
    2. {
    3.     foreach(var item in database)
    4.     {
    5.         if (item.ID == id)
    6.         {
    7.             return item; // returns item with id
    8.         }
    9.     }
    10.    
    11.     return null;
    12. }
     
  5. andymads

    andymads

    Joined:
    Jun 16, 2011
    Posts:
    1,614
    Perhaps I am missing something but why do so many people have trouble with null reference exceptions?

    If you have the line then you know what the references are so just determine which of them is null.

    Code (CSharp):
    1. itemObj.GetComponent<Image>().sprite = itemToAdd.Sprite;
    For this line it's either itemObj, the Image Component, or itemToAdd.

    Either breakpoint the line in the debugger and check each one or just add some print calls before it to try each one.

    e.g.

    Code (CSharp):
    1. print("itemObj="+itemObj);
     
  6. LeftyRighty

    LeftyRighty

    Joined:
    Nov 2, 2012
    Posts:
    5,148
    I would posit that it's usually because they created the code and are bringing more of what they think the code should do to it rather than a cold objective look at what it actually does as written. As outsiders looking at the code we completely lack that (and in a great many posts it's not even suggested let along explained in enough detail to influence the reading of the code).
     
  7. Addison1011

    Addison1011

    Joined:
    Dec 15, 2016
    Posts:
    8
  8. Addison1011

    Addison1011

    Joined:
    Dec 15, 2016
    Posts:
    8
    Thank you I am new to the forums
     
  9. Addison1011

    Addison1011

    Joined:
    Dec 15, 2016
    Posts:
    8
    I am aware of what is null but I don't understand why it is not being initialized.
     
  10. andymads

    andymads

    Joined:
    Jun 16, 2011
    Posts:
    1,614
    I can't see where you included this information in your post.
     
  11. DaveWill

    DaveWill

    Joined:
    Apr 22, 2016
    Posts:
    4
    I think others have said it already but the most likely thing going on is that the Start in your Inventory script is running before the Start that initializes your item database so none of those items exist when you're trying to add them. Maybe try using Awake for the database instead of Start.

    There seems to be a bunch of other weird issues like
    'if (items.ID == -1)' shouldn't compile and neither should 'if (database.ID == id)' and also you have 'return database' for a function that needs to return a single Item not a List<Item> which is what database is.

    This line 'items = itemToAdd' also seems to be not what you really want to do and would also cause a compile error since it's trying to assign an Item object to (I assume) a List<Item>
     
  12. Addison1011

    Addison1011

    Joined:
    Dec 15, 2016
    Posts:
    8
    Why shouldn't that compile?
     
  13. Addison1011

    Addison1011

    Joined:
    Dec 15, 2016
    Posts:
    8
    I tried using Awake but it still threw the Exception. Any other ideas? And Item is a list of items whats the problem of adding a variable of type Item?
     
    Last edited: Feb 7, 2017
  14. Addison1011

    Addison1011

    Joined:
    Dec 15, 2016
    Posts:
    8
    I made it so you guys can also see the inventory Class which holds the AddItem method.
     
  15. Timelog

    Timelog

    Joined:
    Nov 22, 2014
    Posts:
    528
    Because database is a List<Item> and not an Item, which means it has no ID field/property to begin with. Which means the compiler and IDE Should give you the error "Cannot resolve symbol 'ID'". What IDE are you using? Because both MonoDevelop and VS should give you that error.

    And now that I see you have edited the script I see exactly where the main problem is. The private List<T> database is never filled. In your ConstructItemDatabase you use a for loop over the Count of item in database, which, as it is a newly instantiated List, is 0.
     
    DaveWill likes this.