Tuesday, January 14, 2020

c# - Unity JSON parsing Array of Objects problem - error: JSON must represent an object type


I'm trying to use Json to hold game dialog in a text asset file. I've tried to make a barebones project to test this and it is failing with the Error Message: ArgumentException: JSON must represent an object type.


I have a class called LineData which has a few properties each line of dialog contains. In the Json there are just two lines for now. When I import and parse it to try and make a reference to one of the lines of dialog it fails.


Here is all the code:


dialogJson.JSON:


[
{
"lineID": "BEDROOM_DAVE_0001",
"lineDialog": "Yaawwn, up i get for another fun packed day.",

"lineDuration": 3
},
{
"lineID": "BEDROOM_DAVE_0002",
"lineDialog": "Well I think I need a cigarette before I get to work!",
"lineDuration": 3
}
]

LineData.cs



using System;

[Serializable]
public class LineData
{
public string lineID;
public string lineDialog;
public float lineDuration;
}


GameController.cs


using UnityEngine;

public class GameController : MonoBehaviour
{
TextAsset Dialog_Data;

private void Start()
{
Dialog_Data = Resources.Load("txt/dialogJson");


LineData line1 = JsonUtility.FromJson(Dialog_Data.text);
Debug.Log("line 1 dialog = " + line1.lineDialog);
}
}

NOTE: I read here (https://answers.unity.com/questions/1503047/json-must-represent-an-object-type.html) that Unity "can't parse if the json consists of an array of objects". But I don't understand his explanation on how to get around this. Thanks


EDIT: I now have it without error, but the debug message is just empty didnt seem to get any data) . Here is the json now after the edits:


{ "LineData":
[

{
"lineID": "BEDROOM_DAVE_0001",
"lineDialog": "Yaawwn, up i get for another fun packed day.",
"lineDuration": 3
},
{
"lineID": "BEDROOM_DAVE_0002",
"lineDialog": "Well I think I need a cigarette before I get to work!",
"lineDuration": 3
}

]
}

I've also altered the GameController.cs like this (but now it says Index is outside array bounds:


public class GameController : MonoBehaviour
{
TextAsset Dialog_Data;

private void Start()
{

LineData[] lines = new LineData[2];
Dialog_Data = Resources.Load("txt/dialogJson");
lines = JsonUtility.FromJson(Dialog_Data.text);
Debug.Log("line 1 dialog = " + lines[0].lineDialog);
}
}

Answer



When you write a line like this:


LineData line1 = JsonUtility.FromJson(Dialog_Data.text);


You're saying "the JSON in this text string represents exactly one instance of the type LineData". ie. the program is expecting something like this:


{
"lineID": "BEDROOM_DAVE_0001",
"lineDialog": "Yaawwn, up i get for another fun packed day.",
"lineDuration": 3
}

That's everything it needs to be able to populate exactly one LineData object.


When instead you give it JSON like this:


[

{
"lineID": "BEDROOM_DAVE_0001",
"lineDialog": "Yaawwn, up i get for another fun packed day.",
"lineDuration": 3
},
{
"lineID": "BEDROOM_DAVE_0002",
"lineDialog": "Well I think I need a cigarette before I get to work!",
"lineDuration": 3
}

]

Then you're breaking your promise to the program that you were going to give it exactly one instance of type LineData. Instead you've given it two instances packed into an array of type LineData[]. In the eyes of a CPU, this is as different as being handed a chocolate bar to eat versus having a shipping container full of chocolate bars dropped on your foot. ;)


So, we need to tell the program to expect a shipping container. First, by defining what a shipping container full of LineData looks like:


[Serializable]
public class LineDataCollection {
public LineData[] lines;
}

Then formatting our JSON to match this definition (one member named "lines" that holds an array of LineData objects):



{
"lines": [
{ /* Your first line data goes here */ },
{ /* Your second line data goes here... */ }
]
}

Then we need to tell our code to unpack a shipping container worth from the text, instead of just one LineData:


LineDataCollection allLines = JsonUtility.FromJson(Dialog_Data.text);
// Select the first line from the collection, and print its dialogue:

Debug.Log("line 1 dialog = " + allLines.lines[0].lineDialog);

No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...