Json:使用固定的文本格式来存储和表示数据!
优点:简介,清晰,易于人的阅读和编写,易于机器的解析和生成。
类似:XML富文本形式
Json的键值对(类中的变量):
Json的键值对是使用冒号来区分,冒号左边的部分是“键”,右边的部分是“值”;“键”都是使用引号包裹的字符串,每个键值对之间是以逗号分隔
简单的键值对:{ “name” : "小明" }
花括号:表示的是对象
花括号中的每一个键值对都表示这个对象里的变量和变量所对应的值。键名对应对象里的变量名,值对应这个变量名为键名的这个变量所对应的值,变量的类型是根据值来决定的。
方括号:表示的是数组
方括号中的每一个值都代表了数组中的每一个值,值与值之间是以逗号分隔。
{ "items ": [值, 值, 值, 值]}
总结:
1、花括号表示的是对象。
2、冒号表示的是键值对,键值对可以理解为变量。
3、逗号是用来分隔键值对或值。
4、方括号表示的是数组。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class WriteClassToJson { //练习:把Json写成类 //{ // "name":"小明", // "age":80, // "isMan":false //} public class People { public string name; public int age; public bool isMan; } //{ // "name":"小明", // "students":["A","B","C","D"] //} public class Teacher { public string name; //public string[] students; public List<string> students; } //{ // "name":"小明", // "Car":{"name":"名图","color":"write","number":74110} //} public class PeopleCar { public string name; public Car car; } public class Car { public string name; public string color; public int number; } //{ // "name":"小明", // "house": // [ // {"address":"门头沟","size":10} // {"address":"珠海","size":80} // {"address":"地中海","size":800} // ] //} public class PeopleHouse { public string name; public List<House> house; } public class House { public string address; public float size; } //{ // "name":"小明", // "friend": // [ // ["哈士奇","中华田园犬","藏獒"], // ["羊腰子","猪腰子","牛腰子"] // ] //} public class PeopleFriend { public string name; public List<List<string>> friend; } //练习:把类写成Json //写出a,b,c,d对象的Json class Program { static void Main(string[] args) { A a = new A(); a.name = "小明"; a.id = 1111112; a.sex = false; //{ // "name":"小明", // "id":1111112, // "sex":false //} B b = new B(); b.name = "小明"; b.items = new List<string>() { "狗", "车", "腰子" }; //{ // "name":"小明", // "items":[ "狗", "车", "腰子"] //} C c = new C(); c.name = "小明"; c.a = new A(); c.a.name = "小花"; c.a.id = 21; c.a.sex = true; c.b = new B(); c.b.name = "骚粉"; c.b.items = new List<string>() { "狗", "车", "腰子" }; //{ // "name":"小明", // "a":{ "name":"小花","id":21,"sex":true } // "b":{ "name":"骚粉","items":[ "狗", "车", "腰子"] } //} D d = new D(); d.name = "小明"; d.items = new List<DItem>() { new DItem("房子", 1), new DItem("车", 2), new DItem("狗", 3) }; //{ // "name":"小明", // "items": // [ // { "name":"房子", "id":1 }, // { "name":"车", "id":2 }, // { "name":"狗", "id":3 } // ] //} E e = new E(); e.name = "小明"; e.type = EType.B; //{ // "name":"小明", // "type":1 //} } } public class A { public string name; public int id; public bool sex; } public class B { public string name; public List<string> items; } public class C { public string name; public A a; public B b; } public class D { public string name; public List<DItem> items; } public class DItem { public string name; public int id; public DItem(string name, int id) { this.name = name; this.id = id; } } public class E { public string name; public EType type; } public enum EType { A, B, C, D } }
{ "playerName": "尼古拉斯·明", "maxHP": 1000.0, "currentHP": 300.0, "maxExp": 1000.0, "currentExp": 800.0, "level": 1, "gold": 900, "diamonds": 450 }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerData { public float atk; public float defanse; public float thump; public float hp; public float atmpk; public float anger; } public class A { void CreatePlayerData() { PlayerData data = new PlayerData(); data.atk = 100; data.defanse = 100; data.thump = 100; data.hp = 100; data.atmpk = 100; data.anger = 100; } } //{ // "name":"小明", // "class":"Unity3D1803", // "age":80, // "ID":007, // "sex":false //} //{ // "items":["血瓶","蓝瓶","复活币","材料1","材料2"] //} ////Object类型的数组 //{ // "array":["name","age",18,true,false] //}
值的取值范围:
数值(整数或浮点数)
字符串(用双引号包裹)
逻辑值(true或false)
数组(在方括号中)
对象(在花括号中)
Null
常用的类型:
表示对象:
(学生类:name,class,age,ID,sex)
小明,Unity3D1803,80,007,女

表示数组:
(玩家类:items)
血瓶,蓝瓶,复活币,材料1,材料2

写Json的过程中经常出现的问题
1、花括号和方括号前后是否能对应上
2、键值对的键是否用双引号包裹
3、键值对中的冒号的位置
4、最后一个数据是否后有逗号
5、所有的Json的符号都是英文的,注意不要出现中文
6、数据与数据之间是否用逗号分隔开
7、无法解析的情况,键名和变量名不一致
对象转Json:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ObjectToJson : MonoBehaviour { // Use this for initialization void Start () { TestObjectToJson obj = new TestObjectToJson(); //把对象转换成Json字符串,第二个参数是否格式化输出 string str = JsonUtility.ToJson(obj, true); Debug.Log(str); } // Update is called once per frame void Update () { } public class Parent { public string myName; [SerializeField] protected bool isParent; [SerializeField] private int id; public Parent() { myName = "Parent"; isParent = false; id = 12; } } public class TestObjectToJson: Parent { public string name; public int age; [SerializeField]//特性,修饰的是下方的变量,证明这个变量是可序列化和反序列化的 private bool sex;//私有的变量,Json默认不转换 public bool Sex//属性保护字段,确保性别不可修改 { get { return sex; } } public void Func() { } public List<string> list; [SerializeField] private Friend friend;//如果类对象是私有的,还需要添加加[SerializeField] public MyStruct stt; public MyType type; public Friend f1; public TestObjectToJson() { this.name = "小明"; this.age = 80; this.sex = false; list = new List<string>() {"哈士奇", "大金毛", "博美", "泰日天" }; friend = new Friend(); stt = new MyStruct(1, true, "Struct"); type = MyType.B; f1 = null; } } [System.Serializable]//当一个类作为变量类型的时候,需要在定义类的时候,在类的上方加[System.Serializable] public class Friend { public string name; public string address; public int id; public Friend() { this.name = "小红"; this.address = "八宝山"; this.id = 1; } } [System.Serializable] public struct MyStruct { public int id; public bool isStruct; private string name; public MyStruct(int id, bool isStruct, string name) { this.id = id; this.isStruct = isStruct; this.name = name; } } public enum MyType { A, B, C } }
API:JsonUitilty.ToJson(object obj, bool prettyPrint);
1、默认情况下,公有的变量是可序列化的,私有变量如果想要可序列化,需要加特性修饰[SerializeField]。
2、使用该方法来转换对象,只能转换对象和对象的父类里的可序列化的变量,并且转化之后得到的Json的键都对应这些变量名,值都对应这些变量存储的值。
3、对于当一个类作为变量类型的时候,转换过程中,这个类对象一般不会转换成Json,需要在定义类的时候,在类的上方加[System.Serializable],证明这个类的对象是可序列化的
序列化和反序列化:
序列化:把对象转换成字节序列的过程称为序列化。
反序列化:把字节序列转换成对象的过程称为反序列化。
Json是存储和展示数据,只能转换可序列化的字段
属性和方法,不能存储数据,所以不能转换

结构体,和类相同,需要在定义结构体的时候,添加[System.Serializable]
枚举,枚举类型会自动转换成int数值
继承的父类,也会转换出来
public:默认可转换
protected和private:需要添加序列化标识

Json转对象:
多余的键值会自动忽略
多余的变量会自动赋初值
protected和private的变量,在序列化之前,键值不会传递过来
键值和变量可以不是对应关系,顺序可以变换
数组,和变量一样
类,需要添加[System.Serializable],否则会报空引用错误
类,添加私有构造函数,依然可转换,没有公有构造函数,可能会报错
枚举,键值用数字表示
Json转对象,可能存在的报错信息:
NullReferenceException:类可能没加序列化标识
ArgumentException:一定是Json格式有问题
"int":001,会报错,误认字符串
“float”:0.5f,键值的浮点默认是double类型,填float会报错
using System.Collections; using System.Collections.Generic; using UnityEngine; public class JsonToObject : MonoBehaviour { // Use this for initialization void Start () { string json = "{" + ""weight":0.5," + ""name":"小明"," + ""age":"18"," + ""id":"1"," + ""list":[1,2,3,4,5]," + ""cl":{"name":"小花","type":"2"}" + "}"; TestJsonToObject obj = JsonUtility.FromJson<TestJsonToObject>(json); obj.Print(); } // Update is called once per frame void Update () { } public class TestJsonToObject { public string name; public int age; [SerializeField] private int id; [SerializeField] private float weight; public bool sex; public List<int> list; public MyClass cl; public MyType type; public void Print() { Debug.Log("name:" + this.name); Debug.Log("age:" + this.age); Debug.Log("id:" + this.id); Debug.Log("weight:" + this.weight); for (int i = 0; i < list.Count; i++) { Debug.Log("list:" + list[i]); } Debug.Log("cl:" + cl.name); Debug.Log("type:" + this.type); } } [System.Serializable] public class MyClass { public string name; } public enum MyType { A, B, C } }
游戏的存档读档功能
SaveManager,管理存档读档的脚本,用单例模式
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; public class SaveManager { private static SaveManager instance; public static SaveManager Instance { get { if (instance == null) { instance = new SaveManager(); } return instance; } } private SaveManager() { } /// <summary> /// 游戏一启动初始化数据 /// </summary> public void InitData() { Debug.Log("初始化数据"); //从文件中读取数据解析成PlayerData对象, 再把解析完成的对象给PlayerData的单例 Debug.Log(Application.streamingAssetsPath); //Application.persistentDataPath string playerJson = FileTools.ReadFile(Application.streamingAssetsPath + @"PlayerData.txt"); Debug.Log(playerJson); if (playerJson == "") { //如果Json为“” } else { PlayerData data = JsonUtility.FromJson<PlayerData>(playerJson); //把从Json中解析的对象给PlayerData的单例 PlayerData.SetInstance(data); } } /// <summary> /// 关闭游戏保存数据 /// </summary> public void SaveData() { Debug.Log("存储数据"); //在关系游戏时,需要把最新的数据写入到文件中去 //1.把对象转换成Json string json = JsonUtility.ToJson(PlayerData.Instance, true); //2.把转换之后的json写入到文件中 FileTools.WriteFile(Application.streamingAssetsPath + @"PlayerData.txt", json); } }
GameManager,继承Mono,管理启动关闭
using System.Collections; using System.Collections.Generic; using UnityEngine; public class GameManager : MonoBehaviour { // Use this for initialization void Awake() { DontDestroyOnLoad(gameObject);//保证任何场景都有GameManager //游戏一开始初始化数据 SaveManager.Instance.InitData(); } void OnDestroy() { //因为他在场景切换的时候是不销毁的,所以如果OnDestroy被调用了,一定是关闭游戏的时候 //游戏关闭的时候需要调用 存档 SaveManager.Instance.SaveData(); } }
FileTools,工具类,负责读取和写入,using System.IO;
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; /// <summary> /// 这个类的作用,就是读取和写入数据 /// </summary> public static class FileTools { /// <summary> /// 从文件中读取数据 /// </summary> /// <param name="path"></param> /// <returns></returns> public static string ReadFile(string path) { if (!File.Exists(path)) { return ""; } string json = ""; StreamReader sr = new StreamReader(path, System.Text.Encoding.UTF8); try { json = sr.ReadToEnd(); } catch (System.Exception e) { Debug.Log(e.ToString()); } sr.Close(); return json; } /// <summary> /// 把内容写入到文件中 /// </summary> /// <param name="path"></param> /// <param name="json"></param> public static void WriteFile(string path, string json) { if (!File.Exists(path)) { FileStream fs = File.Create(path); fs.Close(); } StreamWriter sw = new StreamWriter(path, false, System.Text.Encoding.UTF8); try { sw.Write(json); } catch (System.Exception e) { Debug.Log(e.ToString()); } sw.Close(); } }
Build问题
StreamingAssets:这个文件夹下的资源都会打包进安装包,并且资源不会进行压缩
Resources:打包的时候资源会进行压缩,压缩Unity的特定格式,无法读写
StreamingAssets:在安装平台是只读的
PersistentDataPath:在安装后出现,可读可写

数据初始化问题