1. 程式人生 > >Unity3D學習(二):使用JSON進行對象數據的存儲讀取

Unity3D學習(二):使用JSON進行對象數據的存儲讀取

進行 存儲路徑 新的 del jpg cati spa 全局變量 .net

前言

前段時間完成了自己的小遊戲Konster的制作,今天重新又看了下代碼。原先對關卡解鎖數據的存儲時用了Unity自帶的PlayerPref(字典式存儲數據)。

讀取關卡數據的代碼:

void Awake ()
    {
        foreach(Transform Child in transform) //Update Level Lists
        {
            //Get Level‘s Name
            string levelname = Child.name.Substring(0,1); 

            //Load level data ,check if it is unlocked
if(PlayerPrefs.GetInt(levelname) == 0) //Set Lock { Child.GetChild(1).gameObject.SetActive(true); } else { Child.GetChild(1).gameObject.SetActive(false); } } }

某一關通關時,解鎖下一關:

public void
LevelCompleted() // level completed { int temp = thisLevel + 1; //next level string nextLevel = temp.ToString(); if (PlayerPrefs.GetInt(nextLevel) == 0) // check if next level is locked PlayerPrefs.SetInt(nextLevel, 1); PlayerPrefs.Save(); StartCoroutine(GameSuccess());
//Show the GameSuccess UI }

個人覺得雖然使用起來方便,但是如果我想存取一些對象結構數據的話很麻煩,於是自己試著寫了個簡單的對象數據存儲。

使用JSON存儲數據

什麽是Json

JSON是一種輕量級的數據交換格式。它的本質其實就是一種對象以鍵值為基礎保存的字符串。

比如有一個Person類:

public class Person
{
   public string name;
   public int age;
   public Person(string _name,int _age)
  {
      // constructor
         name = _name;
         age = _age;
  }
}

//
static void Main()
{
     Person kk = new Person("KK",20);
}

然後實例化一個叫KK的人,那麽它的JSON字符串格式為:{"name": "KK","age":"19"}。

應用:利用JSON對關卡數據進行存儲

這裏使用的是JsonFx,一個基於.NET的JSON操作庫。下載地址1(CSDN) 下載地址2(GitHub)

首先我們需要確定下數據的存儲路徑,這裏定義了一個FilePath類來存放所有路徑(全局變量)。

public class FilePath{
    public static readonly string GAMEDATA_PATH = Application.dataPath + "/GameData"; //遊戲數據的文件夾
    public static readonly string LEVEL_PATH = GAMEDATA_PATH + "/leveldata.txt"; //關卡解鎖數據存儲路徑
//之後有新的數據需要存儲路徑時可以拓展
}

然後將JSON操作和文件IO操作簡單封裝一下:

using JsonFx.Json;
using System.IO;
public class DataManager{
   //保存對象數據
    public static void SaveClass<T>(T saveClass,string path)
    {
       //如果遊戲數據文件夾不存在,創建一個文件夾
        if(!Directory.Exists(FilePath.GAMEDATA_PATH))
            Directory.CreateDirectory(FilePath.GAMEDATA_PATH);
        File.WriteAllText(path, JsonWriter.Serialize(saveClass));
        
    }

   //讀取對象數據
    public static T LoadClass<T>(string path)
    {
        string list = File.ReadAllText(path);
        return JsonReader.Deserialize<T>(list);
    }
}

然後定義一個Level類保存單個關卡數據,需要特別註意的是,JSON序列化的對象必須顯式地指明默認構造函數,不然JsonFx會報錯。

public class Level{
    //關卡編號
    public int LevelNumber { get; set; }
   //關卡是否解鎖
    public bool IsUnlocked { get; set; }
    public Level(){}  //必須提供默認構造函數
    public Level(int _levelnumber,bool _IsUnlocked)
    {
        LevelNumber = _levelnumber;
        IsUnlocked = _IsUnlocked;
    }
}

再定義一個LevelList來存儲所有的關卡。

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

public class LevelLists{

    public List<Level> lists;

    //默認構造函數,用於json序列化與反序列化
    public LevelLists() { }

    /// <summary>
    ///  賦值構造函數,用於遊戲第一次啟動的初始化
    /// </summary>
    public LevelLists(int levels)
    {
        lists = new List<Level>();
        lists.Add(new Level(1, true));  //關卡1肯定必須提前解鎖的
        for(int i = 2; i <= levels;i++ )
        {
           lists.Add(new Level(i, false)); //其余關卡鎖定
        }
    }
}

然後為了在遊戲第一次啟動時初始化數據,我們需要一個腳本FirstLaunch來檢測遊戲是否是第一次啟動。在場景裏創建一個空物體掛上這個腳本即可。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstLaunch : MonoBehaviour {
    public int InitLevelNum; //初始化的關卡數,在編輯器的Inspector裏填寫好,我填寫的是4關
    void Awake()
    {
        Check();
    }

    void Check() //檢查遊戲是否是第一次啟動
    {
        int IsFirstLaunch = PlayerPrefs.GetInt("First");  //獲取這個鍵對應的值,不存在默認為0
        if(IsFirstLaunch == 0) 
        {
            //如果不存在,創建並把值設置為1
            PlayerPrefs.SetInt("First", 1);
            PlayerPrefs.Save();
            InitializeLevelLists();
        }
    }

    void InitializeLevelLists() //在本地初始化關卡列表的數據
    {
       
        LevelLists mylist = new LevelLists(InitLevelNum);
        DataManager.SaveClass<LevelLists>(mylist, FilePath.LEVEL_PATH);
    }
}

然後對於關卡列表,我們寫一個腳本來管理它的狀態

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

public class LevelsControll : MonoBehaviour{
    public GameObject[] Levels;  //關卡選擇
    public GameObject[] Locks;   //關卡鎖
    // Use this for initialization


    void Start()
    {
        Initialize();
    }
    
    void Initialize()   //關卡列表初始化
    {
        //讀取關卡數據
        LevelLists data = DataManager.LoadClass<LevelLists>(FilePath.LEVEL_PATH);
        for(int i = 0; i < Levels.Length;i++)
        {
            //初始化點擊事件監聽
           ClickListener.Get(Levels[i]).onClick += SelectLevels;
            //初始化關卡解鎖狀態
           Locks[i].SetActive(!data.lists[i].IsUnlocked);
        }
    }

    public void SelectLevels(GameObject go)
    {
        int i = 0;
        for(;i < Levels.Length;i++)
        {
            if (go == Levels[i])
                break;
        }
        //Load Level 這裏為了測試直接打印了
        Debug.Log("Load level " + (i + 1));
    }
}

由於關卡選擇直接用的UGUI的Image組件,它沒有UI點擊事件處理,但我們可以自己寫一個腳本實現Unity的點擊事件接口IPointerClickHandler來監聽點擊事件。

using UnityEngine;
using UnityEngine.EventSystems;

public class ClickListener : MonoBehaviour, IPointerClickHandler //註意這是Unity提供的點擊接口
{
    public delegate void VoidDelegate(GameObject go); //事件委托
    public VoidDelegate onClick;

    public static ClickListener Get(GameObject go) //獲取對應GameObject的Listener腳本,沒有就新增一個
    {
        ClickListener listener = go.GetComponent<ClickListener>();
        if (listener == null)
            listener = go.AddComponent<ClickListener>();
        return listener;
    }

    public void OnPointerClick(PointerEventData eventData)
    {
        if (onClick != null)
            onClick(gameObject);
    }
}

OK,然後在場景中弄好UI,掛上腳本,點擊運行。

技術分享

可以發現創建了一個叫GameData的文件夾,然後該文件夾下新建了一個leveldata.txt文件,裏面存儲了關卡的數據。

停止運行,然後這裏我再在文本文件裏把第四關的IsUnlocked屬性修改為true,再運行,發現第四關解鎖了。

技術分享 技術分享

由此,一個簡單的關卡數據存儲也就完成了。

當然這樣沒有什麽安全性,玩家只需要在對應文件夾裏修改這個文本文件就能解鎖了,因此有些時候我們需要對數據進行加密。關於數據加密又是另一個話題了( ̄▽ ̄)。

參考資料

《Unity5.X開發指南》 作者:羅盛謄

UGUI研究院之控件以及按鈕的監聽事件系統(五) 作者:雨凇MOMO

Unity3D學習(二):使用JSON進行對象數據的存儲讀取