1
\$\begingroup\$

i am trying to practice on loading data from json files my problem is about when i try to load the sprite path from the json file to load the image icon from the floder that contain it, i manged to do that but by hard code the path but when i try to use variable to hold the path its failed to load any one can help me in that please

i post the code here

public class InventoryItemDataBase : MonoBehaviour
{
    public allitemData itemsData = new allitemData();
    // Start is called before the first frame update
void Start()
{

    TextAsset asset = Resources.Load("ItemData/ItemDataBase") as TextAsset;
    itemsData = JsonUtility.FromJson<allitemData>(asset.text);

}
public ItemBase itembyid(int id)
{
    for (int i = 0; i < itemsData.ItemBase.Count; i++)
    {
        if (itemsData.ItemBase[i].id == id)
            return itemsData.ItemBase[i];
    }
    return null;
}
}

[System.Serializable]
public class allitemData
{
    public List<ItemBase> ItemBase = new List<ItemBase>();
}

[System.Serializable]
public class ItemBase
{
    public int id, Value;
    public string name, description;
    public static string path;
    public static Sprite Icon = Resources.Load<Sprite>(path);
    public Sprite sprite = Icon;
public ItemBase()
{
    this.id = -1;
}
}

&& json Data

{
  "ItemBase": [
    {
      "id": "0",
      "Value": "7",
      "name": "Teddy Bear",
      "description": "Teddy",
      "path": "IconS/Teddy/"
    },
    {
      "id": "1",
      "Value": "5",
      "name": "UFO",
      "description": "ufoos"
    }]
}

enter image description here

enter image description here

enter image description here

\$\endgroup\$
  • 1
    \$\begingroup\$ Please do not post code as images. Text is much better for reading, copying, searching, accessibility to screen readers, etc. And take the time to format your code so that it is displayed legibly in your post preview. The easier it is for someone to read your question, the faster you'll get answers. \$\endgroup\$ – DMGregory Jun 21 at 18:50
  • \$\begingroup\$ allitemData is a terrible name for a class. First, it should have an initial capital letter to distinguish it from a variable name, AllitemData. Second, you don't need it. You can serialize and deserialize lists directly, JsonUtility.FromJson<List<ItemBase>>(asset.text); \$\endgroup\$ – Draco18s Jun 25 at 14:20
1
\$\begingroup\$

First thing, in this circumstance, static is not going to work (Follow the link if you don't know what static does exactly). Although in this case the compiler gives you this error without the static keyword:

CS0236 A field initializer cannot reference the non-static field, method, or property 'ItemBase.path'

I'm answering this under the assumption that this is the reason why you made it static in the first place, if you had a different reason to do that, because you want it to be static, please notify me and explain your reasons behind that. This error doesn't mean that you should make it static. Because static variables are tied to a Type (ItemBase in your example) instead of the instance of that type. Meaning that if you change it, you change it for all ItemBases, not just the one you want. Also, JSON doesn't (de)serialize it, so that won't work.

As to why you get the above error, see the documentation. This documentation tells you that you should set this value in a method, preferably the constructor. However, because we are Deserializing the constructor is called before the values (id, value, path, name etc.) are overwritten by the JSON values. Meaning we can't use the constructor for this.

There are multiple options to overcome that problem. I'll list 2 simple ones here, although there might be better ones, especially in other JSON libraries that might support things like calling a constructor.

  • Initialize your sprite yourself after deserialization
itemsData = JsonUtility.FromJson(json);
foreach (var item in itemsData.ItemBase)
{
    item.sprite = Resources.Load(item.path);
}
public class ItemBase
{
    public string path; // Set by JSON

    [NonSerialized] public Sprite sprite; // Set by us
}
  • Use a property, that loads the reasource the moment you ask for it. This can have the added advantage/disadvantage that the loading of resources is done at the point when you actually need it, possibly spreading out the load on your cpu.
public class ItemBase
{
    public string path; // Set by JSON

    [NonSerialized] private Sprite _cachedSprite; // Set by us

    public Sprite Sprite
    {
        get
        {
            if (_cachedSprite == null)
                _cachedSprite = Resources.Load(path);
            return _cachedSprite;
        }
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.