Im new to c# and Unity, can't solve this problem about 2 days.
I don't know why, but in ItemOnGround
class on Debug.Log
line always getting this error:
NullReferenceException: Object reference not set to an instance of an object
I tried use FetchItemById
method, but it still wont work. Even if i just copy and paste everything from Slot
class, it still wont work. I tried to attach it to different GameObject but it still wont work. Is it some thread problem or i do something wrong?
Thank you for any help
Here how scripts attached in Unity : Screenshot
So i have 3 .cs
ItemDatabase
using System.Collections;
using System.Collections.Generic;
using System.IO;
using LitJson;
using UnityEngine;
public class ItemDatabase : MonoBehaviour
{
private List<Item> database = new List<Item>();
private JsonData itemData;
void Start()
{
SetLanguagePath();
ConstructItemDatabase();
}
public void SetLanguagePath()
{
itemData = JsonMapper.ToObject(File.ReadAllText(Application.streamingAssetsPath + "/en_Items.json"));
}
public Item FetchItemById(int id)
{
for (int i = 0; i < database.Count; i++)
{
if (database[i].Id == id)
{
return database[i];
}
}
return null;
}
public Item FetchItemBySlug(string slug)
{
for (int i = 0; i < database.Count; i++)
{
if(database[i].Slug == slug)
{
return database[i];
}
}
return null;
}
void ConstructItemDatabase()
{
for (int i = 0; i < itemData.Count; i++)
{
Item newItem = new Item();
newItem.Id = (int)itemData[i]["id"];
newItem.Title = itemData[i]["title"].ToString();
newItem.Value = (int)itemData[i]["value"];
newItem.Power = (int)itemData[i]["stats"]["power"];
newItem.Defense = (int)itemData[i]["stats"]["defense"];
newItem.Vitality = (int)itemData[i]["stats"]["vitality"];
newItem.Description = itemData[i]["description"].ToString();
newItem.Stackable = (bool)itemData[i]["stackable"];
newItem.Type = itemData[i]["type"].ToString();
newItem.Slug = itemData[i]["slug"].ToString();
newItem.Sprite = Resources.Load<Sprite>("Sprites/Items/" + newItem.Slug);
database.Add(newItem);
}
}
}
public class Item
{
public int Id { get; set; }
public string Title { get; set; }
public int Value { get; set; }
public int Power { get; set; }
public int Defense { get; set; }
public int Vitality { get; set; }
public string Description { get; set; }
public bool Stackable { get; set; }
public string Type { get; set; }
public string Slug { get; set; }
public Sprite Sprite { get; set; }
}
Slot
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Slot : MonoBehaviour
{
bool hasItem = true;
private void Start()
{
InitializeSlot();
}
void InitializeSlot()
{
if (hasItem)
{
ItemDatabase database = GameObject.Find("Inventory").GetComponent<ItemDatabase>();
Item item = database.FetchItemById(0);
Debug.Log(item.Slug);
}
}
}
ItemOnGround
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemOnGround : MonoBehaviour
{
void Start()
{
InitializeItem();
}
void InitializeItem()
{
ItemDatabase database = GameObject.Find("Inventory").GetComponent<ItemDatabase>();
Item item = database.FetchItemBySlug("apple");
Debug.Log(item.Slug);
}
}
And en_Items.json
[
{
"id": 0,
"title": "Apple",
"value": 1,
"stats": {
"power": 1,
"defense": 1,
"vitality": 10
},
"description": "Tasty apple",
"stackable": true,
"type": "food",
"slug": "apple"
},
{
"id": 1,
"title": "Plum",
"value": 1,
"stats": {
"power": 1,
"defense": 1,
"vitality": 10
},
"description": "Juicy plum",
"stackable": true,
"type": "food",
"slug": "plum"
}
]
Unity Engine has a specific Order of Execution.
This defines the order at which Unity Callbacks are executed in every script.
For instance, all the Awake()
callbacks in your MonoBehaviours will be executed before any Start()
callback.
That said, it doesn't mean that it governs the order of execution of individual Start()
callbacks from different behaviours.
In your example. It is possible that the Start()
callback of the ItemOnGround
behaviour is invoked before ItemDatabase
's. In which case, you're making calls to an ItemDatabase
that hasn't been initialized yet. So here is what I suggest:
Approach 1:
Knowing that Awake()
is called before Start()
you could initialize your ItemDatabase
by changing Start()
to:
void Awake()
{
SetLanguagePath();
ConstructItemDatabase();
}
Approach 2:
You could adjust the Script Execution Order settings. in Edit > Project Settings.
This allows you to give a priority order to each of your MonoBehaviours.
By giving the script ItemDatabase
a lower number (higher priority) than ItemOnGround
's, you're telling the engine to invoke ItemDatabase.Start()
before ItemOnGround.Start()
.