Load Data JSon in Unity

1.3k Views Asked by At

I'm trying to load the data.json file for a unity project. I don't know where I went wrong. I want to be able to load the level: level1, level2 I have tried some other ways but still not working. Can anyone review and fix the error for me.

I create LoadDataLevel() to handle level and load data I create LevelLoadData which contains the elements of the level object

This is my C#:

public class BaseGameController : MonoBehaviour
{
    public List<Level> levels;
    public TextAsset textAsset;


    public void LoadDataLevel()
    {
        JSONObject jsObj = (JSONObject)JSON.Parse(textAsset.text);
        for (int i = 1; i <= 100; i++)
        {
            string key1 ="level"+i;
            var jsonLevelLoad = jsObj[key1].AsObject;
            levels = new List<Level>();
            if (jsonLevelLoad != null)
            {
                for (int j = 1; j < jsonLevelLoad.Count; j++)
                {
                    if (jsonLevelLoad[j] != null)
                    {
                        Level level = new Level();
                        level.LevelHeight = jsonLevelLoad[i][0].AsInt;
                        var Stars = jsonLevelLoad[j][1].AsArray;
                        if (Stars != null && Stars.Count > 0)
                        {
                            for (int k = 0; k < Stars.Count; k++)
                            {
                                if (Stars[k] != null)
                                    level.Stars.Add(Stars[k].AsInt);
                            }
                        }
                        level.levelId = jsonLevelLoad[j][2].AsInt;

                        var Objects = jsonLevelLoad[j][3].AsArray;
                        if (Objects != null && Objects.Count > 0)
                        {
                            for (int h = 1; h < Objects.Count; h++)
                            {
                                Debug.Log(Objects[h]);
                            }
                        }
                        level.LevelTime = jsonLevelLoad[j][4].AsInt;
                        level.LevelWidth = jsonLevelLoad[j][5].AsInt;
                        levels.Add(level);
                    }
                }
            }
        }
    }

}
[System.Serializable]
public class LevelLoadData
{
    public int LevelHeight;
    public List<int> Stars = new List<int>();
    public int levelId;
    public List<Object> Objects = new List<Object>();
    public int LevelTime;
    public int LevelWidth;
} 

This is my data.json It is list object

 {
   "level1": {
        "LevelHeight": 320,
        "Stars": [],
      "Objects":[], 
        "LevelID": 85,
        "LevelTime": 90,
        "LevelWidth": 820
    },
   "level2": {
        "LevelHeight": 320,
        "Stars": [],
      "Objects":[],
        "LevelID": 88,
        "LevelTime": 90,
        "LevelWidth": 1170
    }
}
1

There are 1 best solutions below

1
On

First of all your loops / indices make not much sense to me.

You are iterating over

for (int i = 1; i <= 100; i++)

so assuming there are exactly 100 items levelX in your json object but you are telling us there are only 2 right now.

And then you try and access

level.LevelHeight = jsonLevelLoad[i][0].AsInt;
var Stars = jsonLevelLoad[j][1].AsArray;
etc...

which makes no sense since the jsonLevelLoad already is the element at index i. Also the iteration over

for (int j = 1; j < jsonLevelLoad.Count; j++)

makes no sense since you already try and index the individual fields by hardcoded indices anyway.

So if something it should probably rather simply be

level.LevelHeight = jsonLevelLoad[0].AsInt;
var Stars = jsonLevelLoad[1].AsArray;
etc..

However I would rather go by he actual names and do

level.LevelHeight = jsonLevelLoad["LevelHeight"].AsInt;
var Stars = jsonLevelLoad["Stars"].AsArray;
etc..

Then you are also for each iteration creating a new levels list

levels = new List<Level>();

so you will always at maximum end up with one single level item.

You want to do this only ONCE.

So if you really want to go fully "manual" here it should probably rather be e.g.

public void LoadDataLevel()
{
    // you want to do this only ONCE
    levels = new List<Level>();

    JSONObject jsObj = (JSONObject)JSON.Parse(textAsset.text);

    // you want to iterate over the actually existing level amount
    for (int i = 1; i <= jsObj.Count; i++)
    {
        var jsonLevelLoad = jsObj["level" + i].AsObject;
        
        // I would not make silent fails for `null` here at all!
        // IF jsonLevelLoad is really `null` now then it is a BUG and we
        // definitely explicitly WANT the exception
        
        Level level = new Level();
        level.LevelHeight = jsonLevelLoad["LevelHeight"].AsInt;
        var stars = jsonLevelLoad["Stars"].AsArray;
        foreach(var star in stars)
        {
            level.Stars.Add(star.AsInt);
        }

        level.levelId = jsonLevelLoad["LevelId"].AsInt;            
        level.LevelTime = jsonLevelLoad["LevelTime"].AsInt;
        level.LevelWidth = jsonLevelLoad["LevelWidth"].AsInt;
        levels.Add(level);
    }
}

However, in general instead of parsing this all "manually" I would suggest you rather use Newtonsoft Json.NET which comes as a Package via the Package manager and is even pre-installed in latest Unity versions.

Then the JSON data structure you have is basically simply a dictionary so you could use

[System.Serializable]
public class LevelLoadData
{
    public int LevelHeight;
    public List<int> Stars = new List<int>();
    // NOTE: the field name MUST match with the name in the JSON file
    // otherwise you will have to explicitly use the attribute [JsonPropertyAttribute(string)]
    // and pass in the desired json field name
    public int LevelId;
    // NOTE: see bottom of answer! Unclear what "Object" is and how exactly you want to deserialize these
    public List<Object> Objects = new List<Object>();
    public int LevelTime;
    public int LevelWidth;
} 

var levelDict = JsonConvert.DeserializeObject<Dictionary<string, LevelLoadData>>(textAsset.text);
levels = new List<Level>();
foreach(var data in levelDict.Values)
{
    levels.Add(new Level
    {
        LevelHeight = data.LevlHeight,
        Stars = data.Stars,
        // NOTE: see below
        //Objects = ???
        LevelID = data.LevelID,
        LevelTime = data.LevelTime,
        LevelWidth = data.LevelWidth
    });
}

Note that in both examples I explicitly omitted the Objects field.

Why? > Because in case this is a UnityEnine.Object it is completely unclear to me what exactly you have standing in your JSON file and how exactly you are going to create these. UnityEngine.Object itself is not serializable into JSON since it will only store a reference and not actually perform a deep serialization I guess.