Unity - JSON

From NoskeWiki
Jump to: navigation, search

About

NOTE: This page is a daughter page of: Unity


Unity / Unity3D is a 3D game engine and on this page I have some snippets of how you can save and load data from JSON using Unity. All code is in C#, as C# is the most powerful language to code Unity games, and also the one with the best JSON support.

Libraries

  • LitJSON
    • Allows converting a class (and all its public variables) to just by calling "JsonMapper.ToJson(person)" and loading with "Person person = JsonMapper.ToObject<Person>(json_string)" without changing the Person class, as shown in this example. With LitJSON also access elements as they are using arrays see how.
  • SimpleJSON
    • A simple JSON loader where you can load with "var N = JSON.Parse(json_string); double version = N["version"].AsFloat;", see example loader. You can't do the same object serialization as LitJSON.
  • Json.NET
    • Looks very powerful - formats output string, but is charged ($20) on AssetStore - versus others which are free.


Using LitJSON in Unity3D

I chose LitJSON because it is more versatile than SimpleJSON, and free (unlike Json.NET). First step is to download the latest version then move the "/bin/LitJSON.dll" file under your Assets (I'd suggest a "Scripts/Plugins" subfolder, but anywhere under the Assets folder should work). Create a "Assets/Scripts/LitJsonDemo.cs" c# file and paste the code below:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using LitJson;
using System;
 
public enum PetType { NONE, CAT, DOG };
 
public class Pet {
  public string name;
  public PetType type;
 
  public Pet() {}  // Must have empty default constructor.
  public Pet(string name_, PetType type_) {
    name = name_;
    type = type_;
  }
}
 
public class Person {
  public string   name;
  public int      age;
  public DateTime birthday;
  public List<Pet> pet;
  public Person() {  // Must have empty default constructor.
    pet = new List<Pet> ();  // Initialize List.
  }
}
 
public class LitJsonDemo : MonoBehaviour {
  void Start () {
    PersonToJson();
    JsonToPerson();
    StartCoroutine(LoadJsonFromWeb());  // Loads from web so needs Coroutine.
    LoadJsonFromResourceFolder();
  }
 
  public static void PersonToJson() {
    Person nelson = new Person();
    nelson.name = "Nelson Mandela";
    nelson.age  = 95;
    nelson.birthday = new DateTime(1918, 7, 18);
    nelson.pet.Add(new Pet("Bubbsters", PetType.DOG));
    nelson.pet.Add(new Pet("Blacky", PetType.CAT));
 
    string json_nelson = JsonMapper.ToJson(nelson);  // Object to json string.
    Debug.Log(json_nelson);
    // Outputs: {"name":"Nelson Mandela","age":95,"birthday":"07/18/1918 00:00:00",
    //           "pet":[{"name":"Bubbsters","type":2},{"name":"Blacky","type":1}]}
  }
 
  public static void JsonToPerson() {
    string json_string = @"
      {
        ""name""     : ""Elizabeth Alexandra Mary"",
        ""age""      : 88,
        ""birthday"" : ""04/21/1926 00:00:00"",
        ""pet""      : [
          {""name"": ""Monty"", ""type"": 2},
          {""name"": ""Willow""}
        ],
        ""field_that_does_not_exist"": 7
      }";  // NOTE: Missing value or extra values are okay - are just skipped.
    Person liz = JsonMapper.ToObject<Person>(json_string);  // Json string to object.
    Debug.Log ("liz's age: " + liz.age);                      // Outputs: 88
    Debug.Log ("liz's 1st pet type: " + liz.pet[0].type);     // Outputs: DOG
 
    // Without using an explicid object:
    JsonData jsonData = JsonMapper.ToObject(json_string);
    Debug.Log ("liz's 2nd pet: " + jsonData["pet"][1]["name"]);   // Outputs: "Willow"
  }
 
  public IEnumerator LoadJsonFromWeb() {  // Special return type when loading from web.
    string url = "http://andrewnoske.com/student/downloads/misc/steve.json";
    WWW www = new WWW (url);
    yield return www;                     // Wait until loaded from web to continue.
    if (www.error != null) { Debug.Log ("ERROR: " + www.error); return false; }
    string json_string = www.data.ToString();
 
    Person steve = JsonMapper.ToObject<Person>(json_string);  // Json string to object.
    Debug.Log("steve's age from URL: " + steve.age);          // Outputs: 44
  }
 
  public static void LoadJsonFromResourceFolder() {
    string resource_path = "text/steve";  // Note that ".json" part must be left out.
    TextAsset text_asset = (TextAsset)Resources.Load(resource_path, typeof(TextAsset));
    if( text_asset == null ) {
      Debug.Log("ERROR: Could not find file: Assets/Resources/" + resource_path);
      return;
    }
    string json_string = text_asset.ToString();
 
    Person steve = JsonMapper.ToObject<Person>(json_string);        // Json string to object.
    Debug.Log ("steve's name from resource file: " + steve.name);   // Outputs: "Steve Irwin"
  }
}


NOTE: This code was expanded from the "LitJSON quickstart guide" to be suitable for Unity. All public member variables are automatically parsed and written out - try changing them to private and they'll be skipped.


To test it out, attach it to the "MainCamera" or any other object in your scene and hit play. To get the last function ("LoadJsonFromResourceFolder") working you'll need to create a "Assets/Resources/text/steve.json" file with this text:

{
  "name": "Steve Irwin",
  "age": 44, 
  "birthday": "02/22/1962 00:00:00",
  "pet": [
    {
      "name":"Sui",
      "type":2
    }
  ]
}


LitJSON Pretty Formatting Options

By default, LitJSON (string json = JsonMapper.ToJson(obj);) will return a string without spaces or newlines. If you would like a pretty indented format you can specify formatting options using JsonWriter:

    Person steve = ...
 
    System.Text.StringBuilder builder = new System.Text.StringBuilder();
    JsonWriter writer = new JsonWriter(builder);
    writer.PrettyPrint = true;
    writer.IndentValue = 2;
    JsonMapper.ToJson(steve, writer);
    Debug.Log(builder.ToString());  // Converts to a pretty/indented JSON string.
    // Outputs: something more similar to XML above.

See also: LitJson simple samples.


LitJSON Limitations/Warnings

The library seems pretty good, but a few major things I've noticed when serializing/deserializing a class:

  • LitJSON only outputs/inputs public variables.
    • Not a bad thing necessarily - you might like to use private for things you don't want output.
  • LitJSON outputs (public) const values, but will (not suprisingly) fail trying to import consts.
    • You may need to move these consts elsewhere or make them private.
  • LitJSON crashes if you try to output (public) float!
    • This is the nastiest problem. My workaround was to make any (public) reals I needed public double.
    • Any public float will produce an error message like this:
      JsonException: Max allowed object depth reached while trying to export from type System.Single
      LitJson.JsonMapper.WriteValue (System.Object obj, LitJson.JsonWriter writer, Boolean writer_is_private, Int32 depth)


Other Pages


Links