2019年5月27日 星期一

在Unity3D使用JSON製作存檔

在Unity3D使用JSON製作存檔

前言

  最近搜尋到Unity3D已經內建支援JSON,想到以前製作存檔是透過PlayerPrefs來儲存相當不好用。想想自己太久沒用Unity3D,該跟上新的製作存檔方式了。

內容

  以前用PlayerPrefs製作存檔不需考慮儲存的位置,因為Unity3D會規劃怎麼儲存,新的做法如下圖
存檔的寫入與讀取

Data是如何轉換成JSON的呢?看以下範例
public class PlayerData
{
  public int intData = 0;
  public float floatData = 3.14159f;
  public PlayerData ptrData = null;//This value will be ignored in json
  public string stringData = "I'm a string";
  public Vector3 vec3Data = Vector3.zero;
  public Matrix4x4 mat44Data = Matrix4x4.identity;
  public List<int> intListData = new List<int>();
  public Dictionary<int, int> intDictData = new Dictionary<int, int>();//This value will be ignored in json
  public Dictionary<string, int> strDictData = new Dictionary<string, int>(); //This value will be ignored in json
}
//
PlayerData data = new PlayerData();
//Convert to json
string jsonStr = JsonUtility.ToJson(data);
//
//Convert to data
PlayerData loadData = JsonUtility.FromJson<PlayerData>(jsonStr);

先把要儲存的資料包成class,不過要注意並不是所有的都可以儲存,會被儲存的資料一定是"public",常見的int、float...等有支援,要注意的是不支援的資料型態,不支援的資料型態是"Reference"與"Dictionary",轉成JSON和轉回資料的部分相當簡單就不多說了。

  接著來看看JSON寫入與讀取的部分,這個部分個人認為使用Binary的方式較為理想(個人比較熟),先看以下範例
using System.IO;
using System.Text; 
//
const string fileName = "playerData.dat";
string filePath = Application.persistentDataPath + "/" + fileName;
string jsonStr = JsonUtility.ToJson(data);
//
// Save
try
{
  File.WriteAllBytes(filePath, Encoding.UTF8.GetBytes(jsonStr));
  Debug.Log("Save OK!");
}
catch (System.Exception e)
{
  Debug.Log("Save failed!");
}
// Load
try
{
  string loadData = Encoding.UTF8.GetString(File.ReadAllBytes(filePath) );
  PlayerData myData = JsonUtility.FromJson<PlayerData>(loadData);
  Debug.Log("Load OK!");
}
catch (System.Exception e)
{
  Debug.Log("Load failed!");
}

寫入的部分要透過"Encodin.UTF8.GetBytes()",而讀取的時候透過"Encodin.UTF8.GetString()"來還原,這個步驟可以讓string的資料可以支援unicode,檔案的開啟與讀取和以前是一樣的。完整的範例如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Text;
public class PlayerData
{
  public int intData = 0;
  public float floatData = 3.14159f;
  public PlayerData ptrData = null;//This value will be ignored in json
  public string stringData = "I'm a string.許";
  public Vector3 vec3Data = Vector3.zero;
  public Matrix4x4 mat44Data = Matrix4x4.identity;
  public List<int> intListData = new List<int>();
  public Dictionary<int, int> intDictData = new Dictionary<int, int>();//This value will be ignored in json
  public Dictionary<string, int> strDictData = new Dictionary<string, int>(); //This value will be ignored in json
}
public class SaveLoadTest : MonoBehaviour
{

  // Start is called before the first frame update
  void Awake()
  {
 
  }
  void Start()
  {
    const string fileName = "playerData.dat";
    string filePath = Application.persistentDataPath + "/" + fileName;
    PlayerData data = new PlayerData();
    data.intListData.Add(9527);
    data.intListData.Add(2266);
    data.intDictData.Add(1, 1234);
    data.intDictData.Add(1024, 7788);
    data.strDictData.Add("abc", 123);
    data.strDictData.Add("abc123", 789);
    //
    string jsonStr = JsonUtility.ToJson(data);
    Debug.Log(jsonStr);
    //
    // Save
    try
    {
      File.WriteAllBytes(filePath, Encoding.UTF8.GetBytes(jsonStr));
      Debug.Log("Save OK!");
    }
    catch (System.Exception e)
    {
      Debug.Log("Save failed!");
    }

    // Load
    try
    {
      
      string loadData = Encoding.UTF8.GetString(File.ReadAllBytes(filePath) );
      Debug.Log("loadData:"+loadData);
      PlayerData myData = JsonUtility.FromJson<PlayerData>(loadData);

      Debug.Log("Load OK!");
    }
    catch (System.Exception e)
    {
      Debug.Log("Load failed!");
    }
  }

    // Update is called once per frame
    void Update()
    {
        
    }
}


參考資料

Introduction to Saving and Loading
Unity 遊戲存檔機制淺談,從序列化 (Serialization) 到儲存裝置 (Storage)

沒有留言:

張貼留言