纳金网
标题:
游戏资源的导出与加载 (转载)
[打印本页]
作者:
王者再临
时间:
2014-11-29 05:31
标题:
游戏资源的导出与加载 (转载)
AssetBundle的知识官网的API已经介绍的比较详细了。AssetBundle是一个Unity3D自带的存储数据的类,他可以把你的游戏资源导出为后缀名为.assetbundle的文件。
这里就要涉及到一个unityEditor中的一个类buildPipeline,它有几个静态方法:[url=]BuildAssetBundle[/url]等等,有过这个类就可以实现导出功能。如果你把一个预设导出成为assetbundle文件后。该预设的组件都是全的,不会没有。下面是我写的导出代码,导出代码:
[MenuItem("AssetBundle/Export AssetBundle")]
public static void ExportAssetBundle()
{
GameObject[] objs = Selection.gameObjects;
for (int iter = 0; iter < objs.Length; ++iter)
{
GameObject obj = objs[iter];
Object prefab = PrefabUtility.GetPrefabParent(obj);
obj = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
GameObject prefabObj = _GetClonePrefab(obj) as GameObject;
_ExportProtocol(prefabObj);
_Export(prefabObj);
}
}
static void _ExportProtocol(GameObject go)
{
UIProtocolList protocoList = new UIProtocolList();
protocoList.RootName = go.name;
_TakeOffUIData(go, protocoList);
ExportProtocol(protocoList);
}
static void _TakeOffUIData(GameObject go, UIProtocolList list)
{
_SaveObjectInformation(go, list);
for (int iter = 0; iter < go.transform.childCount; ++iter)
{
_TakeOffUIData(go.transform.GetChild(iter).gameObject, list);
}
}
static void _SaveObjectInformation(GameObject go, UIProtocolList list)
{
UISprite sprite = go.GetComponent<UISprite>();
if (sprite != null)
{
UIProcotol procotol = new UIProcotol();
procotol.Name = sprite.spriteName;
procotol.Template = sprite.atlas.name;
procotol.Type = (byte)ExportType.SPRITE;
procotol.Hierarchy = _GetChildHierarchy(go);
sprite.atlas = null;
list.ProcotolList.Add(procotol);
}
//other type....
//.....................
}
static string _GetChildHierarchy(GameObject go)
{
if (go == null)
{
return string.Empty;
}
Transform parent = go.transform;
string hierarchy = "\\";
while (parent != null)
{
for (int iter = 0; iter < parent.childCount; ++iter)
{
GameObject obj = parent.GetChild(iter).gameObject;
if (object.ReferenceEquals(go, obj))
{
hierarchy += "/" + iter.ToString();
break;
}
}
go = parent.gameObject;
parent = parent.transform.parent;
}
hierarchy += "\\";
return hierarchy;
}
static void ExportProtocol(UIProtocolList list)
{
MemoryStream stream = UIProtocolList.Serialize(list);
stream.Position = 0;
System.Byte[] datas = new byte[stream.Length];
BlodStream blod = ScriptableObject.CreateInstance<BlodStream>();
stream.Read(datas, 0, datas.Length);
blod.LoadDatas(datas);
string path = "Assets/blod.asset";
AssetDatabase.CreateAsset(blod, path);
Object o = AssetDatabase.LoadAssetAtPath(path, typeof(BlodStream));
BuildPipeline.BuildAssetBundle(o, null, "assetbundle/" + list.RootName + "protocol.assetbundle", BuildAssetBundleOptions.CollectDependencies);
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(o));
}
static void _Export(GameObject prefab)
{
List<Object> objs = new List<Object>();
objs.Add(prefab);
BuildPipeline.BuildAssetBundle(null, objs.ToArray(), "assetbundle/" + prefab.name + ".assetbundle", BuildAssetBundleOptions.CollectDependencies);
AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(prefab));
}
static Object _GetClonePrefab(GameObject go)
{
Object tempPrefab = PrefabUtility.CreateEmptyPrefab("Assets/" + go.name + ".prefab");
tempPrefab = PrefabUtility.ReplacePrefab(go, tempPrefab);
Object.DestroyImmediate(go);
return tempPrefab;
}
复制代码
这里段代码的目的是导出在场景中的预设,想一下,假设你在做一个UI界面,你做完了,要把它导出,你可以执行这段代码。他会在中间过程中生成一个原预设的Clone,在这个Clone会出现在Hierarchy层中,再在Assets目录下创建一个空预设,把Clone的预设付到空预设,再删除Clone,那么对这个在Assets下预设的操作就不会影响到最原来的预设了。
因为NGUI中导出包含图片的资源后,会变得很大,主要原因Altas是把一张张图片组合成一张大图,你要导出一张图时,是一整张导出的,所以这么大。我的解决方法是导出把他们的altas,sprite变为空,这些altas,sprite的节点位子,信息,记录都放在另外一个asstbundle文件里。信息比如当前包含altas或sprite的游戏物体所在整个游戏物体的索引,还有该组件的类型,还有altas,sprite的名字等信息。我这里自己定义了两个类一个是UIProtocolList,UIProcotol.
public enum ExportType
{
ATLAS,
FONT,
TEXTURE,
SPRITE
}
[Serializable]
public class UIProcotol
{
public string Name;
public string Template;
public string Hierarchy;
public byte Type;
}
复制代码
[Serializable]
public class UIProtocolList
{
public string RootName;
public List<UIProcotol> ProcotolList = new List<UIProcotol>();
public static MemoryStream Serialize(UIProtocolList list)
{
MemoryStream stream = new MemoryStream();
BinaryFormatter b = new BinaryFormatter();
b.Serialize(stream, list);
return stream;
}
public static UIProtocolList Dserialize(MemoryStream stream)
{
UIProtocolList list = new UIProtocolList();
BinaryFormatter b = new BinaryFormatter();
list = b.Deserialize(stream) as UIProtocolList;
return list;
}
}
复制代码
UIProcotol这个类是来表示单个Altas或是其他,UIProtocolList是表示该游戏物体所有的Altas或其他资源。这两个类都是序列化类。为了加载他们时反序列话回来使用。如果要导出为assetbundle文件的自己定义类型类的文件的话,那个类必须继承ScriptableObject。如果不这样Unity3D会报错的。我写了一个类似流一样的类:
public class BlodStream : ScriptableObject
{
public Byte[] Datas { get { return _Datas; } }
public void LoadFile(string fileName)
{
if (!File.Exists(fileName))
{
Debug.Log("the file is empty");
return;
}
FileStream br = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
if (br == null)
{
return;
}
_Datas = new Byte[br.Length];
br.Read(_Datas, 0, _Datas.Length);
}
public void SaveFile(string fileName)
{
FileStream bw = File.Create(fileName);
if (bw != null)
{
bw.Write(_Datas, 0, _Datas.Length);
bw.Close();
}
}
public void LoadDatas(Byte[] datas)
{
_Datas = datas;
}
public byte[] _Datas;
}
复制代码
作者:
hyui
时间:
2014-11-29 17:16
very good code share
作者:
oelongeo
时间:
2014-11-30 11:33
顶一个! ! 谢谢指导! 还在学习...尚未完全理解
作者:
大大虾
时间:
2014-11-30 15:02
非常感谢分享宝贵经验!!
欢迎光临 纳金网 (http://go.narkii.com/club/)
Powered by Discuz! X2.5