在unity中序列化儲存遊戲元素
阿新 • • 發佈:2019-01-23
由於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的功能更多更好用啊。