0
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

string filename = "data.json";
string jsonString;
string path;

[System.Serializable]
public class LevelGrid
{
    public string[] rows;
}

[System.Serializable]
public class Levels
{
    public LevelGrid[] levels;
}

void LoadGrid()
{
    // Load data
    string path = Application.streamingAssetsPath + "/" + filename;
    jsonString = File.ReadAllText(path);
    var levelBricks = JsonUtility.FromJson<Levels>(jsonString);

    // DOESNT WORK
    Debug.Log(levelBricks.levels[0]); 

}

My data.json is:

 {
     "Levels": [
         {"Level1": ["1,1,1,1,1", "1,1,1,1,1", "1,1,1,1,1"]},
         {"Level2": ["1,1,1,1,1", "1,1,1,1,1", "1,0,1,0,1"]}
     ]
 }

Something is wrong with the levelBricks int and nothing is properly being loaded from json. What am I doing wrong? The Debug.Log gives an error and if I only Debug.Log "levelBricks", all I get is "Levels". I'd like to be able to access the arrays in Level1 and Level2.

Rach
  • 17
  • 5
  • 1
    What is `JsonUtility.FromJson`? – DavidG Jul 05 '18 at 14:13
  • Try it with json.net instead of JsonUtility https://www.newtonsoft.com/json – Sean T Jul 05 '18 at 14:14
  • OP is using Unity, as far as I know JSON.NET is not available in Unity. Besides that, the error is pretty clear to see. The `Level1` and `Level2` keys are dynamic, the C# classes do not reflect that... – maccettura Jul 05 '18 at 14:18
  • Not sure about Unity, but you could deserialise into JSON.Net with this class `public class Levels { public Dictionary[] levels; }` so that might work. – DavidG Jul 05 '18 at 14:23
  • @DavidG would that work though? `Levels` is an array of objects, using a dictionary would yield an object, not an array of objects. At least as far as my experience with Json.NET – maccettura Jul 05 '18 at 14:24
  • No, Dictionary are not supported in Unity default Json library https://docs.unity3d.com/Manual/script-Serialization.html read note here – LiefLayer Jul 05 '18 at 14:25
  • @maccettura Yeah, works in JSON.Net, go figure! https://i.stack.imgur.com/BJdJq.png – DavidG Jul 05 '18 at 14:26
  • @DavidG oh I missed the array designation on the Dictionary object. My bad! I would say thats the answer, you'll have my vote – maccettura Jul 05 '18 at 14:29
  • @maccettura Yeah, it's nasty but it works. Don't see any reason why you can't add JSON.Net to Unity though, it target Net Standard now so should work anywhere. – DavidG Jul 05 '18 at 14:31
  • @DavidG I think its because Unity is built off Mono. I tried researching it and it looks like all the Json.NET packages available for it are ripoffs and not made by Newtonsoft. I have never used Unity though so I am far from knowledgeable on the subject. – maccettura Jul 05 '18 at 14:32
  • @maccettura Same here. JSON.Net website says it works under Mono though, should just be a case of importing the DLL. – DavidG Jul 05 '18 at 14:34
  • 1
    Having said that, if I were using JSON.Net, I'd probably use a custom converter for the dynamic property. – DavidG Jul 05 '18 at 14:34
  • @DavidG Too many reasons. It's not all about working on Windows. Unity is multiplatform and that will fail on platforms such as iOS due to AOT. Also, Unity' recently added 4.5 net support which is the minimum req for Json.Net. Only those with the latest Unity version can use this but the AOT issues still remains. Luckily, there is a Json.Net forked version made for Unity to solve these issues [here](https://github.com/SaladLab/Json.Net.Unity3D) – Programmer Jul 05 '18 at 14:39
  • You should really look at my updated answer. I just edited two minutes after I said that the main problem was the variable. With my answer you should be able to do everything with the base json unity library – LiefLayer Jul 05 '18 at 14:42
  • @Programmer That library is now 2 years old. JSON.Net now targets .NET Standard 1, 1.3 and 2.0 and is fully portable. – DavidG Jul 05 '18 at 14:43
  • The oldness doesn't really matter. It still works and used by many Unity users. I also heard that JSON.Net was updated to support lower .NET versions but I haven't tried those to test it and simply supporting those version doesn't mean that crashing issues caused by AOT or unsupported features are now solved. – Programmer Jul 05 '18 at 14:50
  • @Programmer Yes, I'm well aware of those things, but I use JSON.Net on all sorts of platforms right now (Windows, .NET Core, Linux, Android, iOS etc.) and it works perfectly. I see no reason it wouldn't work in Unity too – DavidG Jul 05 '18 at 14:59
  • Im reading I should just wrap the array [System.Serializable] public class BrickGrid { [System.Serializable] public class LevelGrid { public string[] levels; } public LevelGrid[] levels; } – Rach Jul 05 '18 at 15:50
  • @Ranch Like I said in my answer you will not be able to serialize 2 arrays of string if your class have just 1 array of string. Just try it, you will know that my answer is the right one if you want to use the default Unity library (than you can accept it). Also, yes the object wrap is correct – LiefLayer Jul 05 '18 at 15:55

1 Answers1

-1

The main problem is that your class variables should use the same name of your json. example: public string[] rows;

should be public string[] Levels;

EDIT. you need a serializable class with

    [SerializeField] ClassForLevel12[] levels;

    public ClassName() {
    }

    public ClassName(ClassForLevel12[] levels) {
      this.levels = levels;
    }

and getter/setter

    public static ClassName SaveFromString(string 
jsonString) {
          return JsonUtility.FromJson<ClassName>(jsonString);
         }

    public string SaveToString() {
      return JsonUtility.ToJson(this);
    }

and a serializable class ClassForLevel12 with 2

    public string[] level1;
    public string[] level2;

(and everything like the other class).

Final EDIT. Ok this is what you need, just copy, paste and understand:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class MyLevels{
  [SerializeField] List<LevelGrid> levels;
  public MyLevels(){}
  public MyLevels(List<LevelGrid> levels){
    this.levels = levels;
  }
  public List<LevelGrid> Levels{
    get { return levels; }
    set { levels = value; }
  }
  //from a jsonstring to an object
  public static MyLevels SaveFromString(string jsonString){
    return JsonUtility.FromJson<MyLevels>(jsonString);
  }
  //object to json
  public string SaveToString(){
    return JsonUtility.ToJson(this);
  }

}

Second class

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[System.Serializable]
public class LevelGrid{
    [SerializeField] string[] level1;
    [SerializeField] string[] level2;
    public LevelGrid() {
    }
    public LevelGrid(string[] level1, string[] level2) {
      this.level1 = level1;
      this.level2 = level2;
    }
    public string[] Level1{
      get { return level1; }
      set { level1 = value; }
    }
    public string[] Level2{
      get { return level2; }
      set { level2 = value; }
    }
    //from a jsonstring to an object
    public static LevelGrid SaveFromString(string jsonString) {
      return JsonUtility.FromJson<LevelGrid>(jsonString);
    }
    //object to json
    public string SaveToString() {
      return JsonUtility.ToJson(this);
    }
}

Now you can just call

    string jsonString = "{ \"levels\": [ {\"level1\": [\"1,1,1,1,1\", \"1,1,1,1,1\", \"1,1,1,1,1\"]},{\"level2\":[\"1,1,1,1,1\", \"1,1,1,1,1\", \"1,0,1,0,1\"]}]}";
    MyLevels levelBricks = MyLevels.SaveFromString(jsonString);
    Debug.Log(levelBricks.Levels[0].Level1[0]);
LiefLayer
  • 977
  • 1
  • 12
  • 29
  • The `Levels` class has a property called `levels`. Changing rows to `Levels` wont fix that – maccettura Jul 05 '18 at 14:25
  • it's still missing level1 and level2. Also the rows variable is wrong as a top serializable – LiefLayer Jul 05 '18 at 14:28
  • Now, what happens when json contains `level3`, `level4`? You see, this isn't right – Programmer Jul 05 '18 at 14:44
  • the json should reflect the data in the class. Unity library only get a basic support for primitive types and few complex types (like List). I'm sure there are many good and better libraries out there that are better than Unity default, but if you need to use Unity3d default library this is a correct answer. https://docs.unity3d.com/Manual/script-Serialization.html this is docs – LiefLayer Jul 05 '18 at 14:48
  • Im not sure I understand this answer. Could you write it out exactly like Id code it?@Mah – Rach Jul 05 '18 at 16:22
  • @Rach it should be clear now. You just need to copy&paste. If there is anything that you do not undestand just ask. it should be a really easy to read code now. – LiefLayer Jul 05 '18 at 18:46
  • Also... you can use [SerializeField] instead of public like in my first example for variables, if you don't want them to be public (after all you need getter/setter) – LiefLayer Jul 05 '18 at 18:51
  • @Rach Ok I tried it right now. Just copy&paste does not work because there is a naming problem... I'm editing the answer right now with the full working and tested code. – LiefLayer Jul 06 '18 at 10:08
  • Debug.Log(levelBricks.Levels[1].Level2[0]); Level 2 doenst work @Mah – Rach Jul 06 '18 at 10:46
  • @Rach you can thank me by accept my answer and upvote. so that everybody will know that it's the right answer to look at – LiefLayer Jul 06 '18 at 10:55