StonksMan9000
StonksMan9000

Reputation: 311

Parsing JSON with 2D arrays in Unity C#

I am working with Unity and Python and sending data over UDP to my Unity client. I am sending a JSON which reaches my Unity application successfully. I can't figure out how to properly parse this JSON. I have tried :

JsonUtility.FromJson<T>(...)

but the result wasn't correct. I implemented a [System.Serializable] class which contained data types

List<List<int>> landmarks;
List<double> eulerAngles;
List<List<double>> boxPoints;

And initialized these in my constructor using

landmarks = new List<List<int>>(); 
...

Every time I try to print the result, all my variables are empty.

My JSON looks like this -

{
    "eulerAngles": [6.2255, -15.8976, -0.5881], 
    "boxPoints": [
        [194.05965, 194.15782], 
        [182.35829, 189.05042], 
        [6 more...]
    ], 
    "landmarks": [
        [196, 225], 
        [197, 242], 
        [199, 258], 
        [65 more..]
     ]
}

Any help appreciated.

Upvotes: 2

Views: 5599

Answers (1)

derHugo
derHugo

Reputation: 90779

Your JSON is still strangly formatted and I don't understand your data structure.

Why are you storing everything in List<int[]> while the values you get are clearly float (or double) values?

If something it should probably be

[Serializable]
public class JsonData
{
    // here maybe int is ok at least from your data it seems so
    public List<int[]> landmarks = new List<int[]>();

    // for those you clearly want floats
    public List<float[]> eulerAngles = new List<float[]>();
    public List<float[]> boxPoints = new List<float[]>();
}

Have a look at this JSON to c# converter!

BUT anyway Unity's JsonUtility seems not to support the deserialization of nested arrays and lists! I guess the reason is that while other primitive data types have a default value that is different from null, List and arrays are null be default and have to be initialized before filling them. JsonUtility seems to not support that. I think it is related to

Note that while it is possible to pass primitive types to this method, the results may not be what you expect; instead of serializing them directly, the method will attempt to serialize their public instance fields, producing an empty object as a result. Similarly, passing an array to this method will not produce a JSON array containing each element, but an object containing the public fields of the array object itself (of which there are none). To serialize the actual content of an array or primitive type, it is necessary to wrap it in a class or struct. (JsonUtility.ToJson)

and

a field of type T will have value default(T) - it will not be given any value specified as a field initializer, as the constructor for the object is not executed during deserialization (JsonUtility.FromJson)


However, why even take them as arrays where every of your arrays only has one element anyway when it seems (and your names and title say) you rather want to store tuples of allways 2 and 3 numbers?

In case you can change the JSON format it seems like you rather would want something like

[Serializable]
public class JsonData
{
    // here maybe int is ok at least from your data it seems so
    public List<Vector2Int> landmarks = new List<Vector2Int>();

    // for those you clearly want floats
    public List<Vector3> eulerAngles = new List<Vector3>();
    public List<Vector2> boxPoints = new List<Vector2>();
}

And your JSON should than rather look like

{
    "eulerAngles": [
        {"x":6.2255, "y":-15.8976, "z":-0.5881},
        ...
    ], 
    "boxPoints": [
        {"x":194.05965, "y":194.15782}, 
        {"x":182.35829, "y":189.05042}, 
        ...
    ], 
    "landmarks": [
        {"x":196, "y":225}, 
        {"x":197, "y":242}, 
        {"x":199, "y":258}, 
        ...
     ]
}

The simplest way to see how your JSON should actually look like would be to take your JsonData class and serialize it once so you see what Unity expects as JSON.

var testData = new JsonData();
// fill it with example values
testData.eulerAngles = new List<Vector3>()
{
    new Vector3(6.2255f, -15.8976f, -0.5881f)
};
testData.boxPoints = new List<Vector2>()
{
    new Vector2(194.05965f, 194.15782f), 
    new Vector2(182.35829f, 189.05042f)
};
testData.landmarks = new List<Vector2Int>()
{
    new Vector2Int(196, 225),
    new Vector2Int(197, 242),
    new Vector2Int(199, 258)
}

var result = JsonUtility.ToJson(testData);

If changing the JSON format is not an option you could instead have a look at SimpleJSON which doesn't deserialize directly into a class instance but rather to a JSONNode which can contain nested lists and arrays e.g.

var jsonData = JSON.Parse(yourJson);
var firstEuerAngles = jsonData["eulerAngles"][0];

Upvotes: 3

Related Questions