1. 程式人生 > >在unity中序列化儲存遊戲元素

在unity中序列化儲存遊戲元素

由於unity在執行時只能動態載入Resources目錄下的檔案,但是在有的情況下一些資源不能直接放在Resources目錄下(比如UGUI的需要打包的散圖)。如果需要動態載入在Resources目錄外的遊戲資源時,比較簡單的方法是把這些資源放在一個prefab中,然後把相應的prefab放在Resources目錄下。

參考了前輩寫的一些東西,發現了另一種方法,即序列化這些資源的引用,把序列化之後的例項掛在一個prefab上,再把該預設放在Resources資料夾下,這樣也可以實現動態載入遊戲資源。並且和第一種方法相比,這樣一個預設中可以放的遊戲資源的引用數量可以很多,目錄結構更清晰。

下面是一個例子,把sprite圖的引用序列化在一個prefab當中:
其中Sprite資料夾在Assets目錄下,可以有子資料夾,生成的prefab儲存在Assets/Resources/Sprite下

public class SpriteList : MonoBehaviour
{
    [HideInInspector]
    [SerializeField]
    List<Sprite> spriteList = new List<Sprite>();

    public Sprite GetSprite(string name)
    {
        Sprite sprite = spriteList.Find((Sprite sp) => { return sp.name == name; });
        return
sprite; } public void AddSprite(Sprite sp) { spriteList.Add(sp); } }

下面是儲存資源的方法:

    static void SaveSprite()
    {
        string targetDir = Application.dataPath + "/Resources/Sprite";

        if (!Directory.Exists(targetDir))
            Directory.CreateDirectory(targetDir);

        DirectoryInfo fromDirInfo = new
DirectoryInfo(Application.dataPath + "/Sprite"); foreach (DirectoryInfo dirInfo in fromDirInfo.GetDirectories()) { MakePrefab(dirInfo, fromDirInfo, targetDir); } } static void MakePrefab(DirectoryInfo dirInfo, DirectoryInfo fromDirInfo, string targetDir) { string fieldName = dirInfo.Name; FileInfo[] allPngFiles = childDir.GetFiles("*.png", SearchOption.AllDirectories); GameObject go = new GameObject(fieldName); SpriteList sl = go.AddComponent<SpriteList >(); string prefabParentFieldPath = string.Format("{0}/{1}", targetDir, fieldName); if (!Directory.Exists(prefabParentFieldPath)) { Directory.CreateDirectory(prefabParentFieldPath); } //將sprite序列化在SpriteList 類中 foreach (FileInfo pngFile in allPngFiles) { string assetPath = pngFile.FullName.Substring(pngFile.FullName.IndexOf("Assets")); Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>(assetPath); if (sprite == null) { Debug.LogWarning(string.Format("It's not a sprite which is at \"{0}\"", assetPath)); continue; } sl.AddSprite(sprite); } // 在對應資料夾內生成預設 string prefabAllPath = string.Format("{0}/{1}.prefab", prefabParentFieldPath, fieldName); string prefabPath = prefabAllPath.Substring(prefabAllPath.IndexOf("Assets")); PrefabUtility.CreatePrefab(prefabPath, go); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); GameObject.DestroyImmediate(go); }

以上這一步是在編輯器中執行的,生成prefab之後就可以在遊戲執行時動態呼叫了,呼叫方法如下:

    public static Sprite GetSpriteByName(string folderName, string spriteName)
    {
        string Path = string.Format("Sprite/{0}", folderName);
        GameObject go = Resources.Load(Path) as GameObject;
        if (go != null)
        {
            SpriteList  sl = go.GetComponent<SpriteList >();
            if (sl != null)
            {
                return sl.GetSprite(spriteName);
            }
        }
        return null;
    }

除sprite外,unity中的其他內建元素也可以通過類似的方式序列化。不過用了UGUI之後發現還是NGUI的功能更多更好用啊。