使用UnityEditor製作視覺化打包AssetBundle(一)
阿新 • • 發佈:2018-12-19
基本流程
- 建立xml檔案,將xml內容解析到實體類中
- 繪製UnityEditor視窗,將xml內容繪製到視窗中
- 打包AssetBundle
- 載入AssetBundle(非同步和同步)
準備原材料:xml和entity實體類
<?xml version="1.0" encoding="utf-8"?> <!-- AssetBundleConfig.xml --> <Root> <AssetBundle> <Item Name="MainCity_Role_Cike" Tag="Role" Version="1" Size="0" ToPath="/Role/"> <Path Value="Resources\RolePrefab\RolePlayer\MainCity_Role_Cike.prefab" /> </Item> <Item Name="Scene_Main" Tag="Scene" Version="1" Size="0" ToPath="/Scene/"> <Path Value="Scene\SceneMap\Scene_Main.unity" /> </Item> </AssetBundle> </Root>
// AssetBundleEntity.cs using System.Collections.Generic; public class AssetBundleEntity { /// <summary> /// 打包指定專用Key(唯一性) /// </summary> public string Key; /// <summary> /// 名稱 /// </summary> public string Name; /// <summary> /// 標記 /// </summary> public string Tag; /// <summary> /// 版本號 /// </summary> public int Version; /// <summary> /// 大小(K) /// </summary> public long Size; /// <summary> /// 將要存放的資料夾 /// </summary> public string ToPath; /// <summary> /// 資源存放路徑集合 /// </summary> private List<string> m_PathList = new List<string>(); public List<string> PathList { get { return m_PathList; } } }
PathList: 後面會使用到這個屬性,通過這個屬性將所有資源打包Assetbundle,儲存在自己定義的路徑/ToPath/下
XML讀取類的編寫
// AssetBundleDAL.cs using System.Collections.Generic; using System.Xml.Linq; public class AssetBundleDAL { /// <summary> /// xml路徑 /// </summary> private string m_XMLPath; /// <summary> /// 返回的AssetBundle實體集合 /// </summary> private List<AssetBundleEntity> m_List = null; public AssetBundleDAL(string xmlPath) { this.m_XMLPath = xmlPath; m_List = new List<AssetBundleEntity>(); } #region 讀取xml檔案 GetList /// <summary> /// 讀取xml檔案 儲存到實體集合中 /// </summary> public List<AssetBundleEntity> GetList() { m_List.Clear(); //讀取xml 把資料新增到mlist中 XDocument xDoc = XDocument.Load(m_XMLPath); XElement root = xDoc.Root; XElement assetBundleNode = root.Element("AssetBundle"); IEnumerable<XElement> itemList = assetBundleNode.Elements("Item"); int keyIndex = 0; foreach(XElement item in itemList) { AssetBundleEntity abEntity = new AssetBundleEntity(); abEntity.Key = "key" + ++keyIndex; abEntity.Name = item.Attribute("Name").Value; abEntity.Tag = item.Attribute("Tag").Value; abEntity.ToPath = item.Attribute("ToPath").Value; abEntity.Version = item.Attribute("Version").Value.ToInt(); abEntity.Size = item.Attribute("Size").Value.ToLong(); IEnumerable<XElement> paths = item.Elements("Path"); foreach(XElement path in paths) { abEntity.PathList.Add(string.Format(@"Assets\{0}", path.Attribute("Value").Value)); } m_List.Add(abEntity); } return m_List; } #endregion }
通過GetList()就可以直接獲取到所有的entity實體了
下面進行EditorWindow的編寫 -- 也就是視覺化的AssetBundle介面編寫
// AssetBundleWindow.cs
using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
public class AssetBundleWindow : EditorWindow
{
private AssetBundleDAL abDAL = null;
//AssetBundle實體列表
private List<AssetBundleEntity> assetBundleEntities = null;
//字典 Assetbundle名字 - 是否打包選中
private Dictionary<string, bool> m_Dict;
//型別陣列
private string[] arrTag = { "All", "Scene", "Role", "Effect", "Audio", "None" };
private int tagIndex = 0;
//編譯平臺數組
private string[] arrBuildTarget = { "Windows", "iOS", "Android" };
string xmlpath = "";
//ScrollView的Scroll位置
private Vector2 pos;
#if UNITY_STANDALONE || UNITY_EDITOR
private BuildTarget target = BuildTarget.StandaloneWindows;
private int buildTargetIndex = 0;
#elif UNITY_IPHONE
private BuildTarget target = BuildTarget.iOS;
private int buildTargetIndex = 1;
#elif UNITY_ANDROID
private BuildTarget target = BuildTarget.Android;
private int buildTargetIndex = 2;
#endif
void OnEnable()
{
// 自定義xmlpath 這裡我寫死了
xmlpath = Application.dataPath + @"\Script\Editor\AssetBundleConfig.xml";
m_Dict = new Dictionary<string, bool>();
if (!string.IsNullOrEmpty(xmlpath))
{
abDAL = new AssetBundleDAL(xmlpath);
assetBundleEntities = abDAL.GetList();
}
// 預設給所有的選項打勾
for (int i = 0; i < assetBundleEntities.Count; i++)
{
m_Dict[assetBundleEntities[i].Key] = true;
}
}
private void OnGUI()
{
if (assetBundleEntities == null) return;
#region 按鈕行
GUILayout.BeginHorizontal("box");
tagIndex = EditorGUILayout.Popup(tagIndex, arrTag, GUILayout.Width(100));
if (GUILayout.Button("選定Tag", GUILayout.Width(100)))
{
EditorApplication.delayCall = OnSelectTagCallback;
}
buildTargetIndex = EditorGUILayout.Popup(buildTargetIndex, arrBuildTarget, GUILayout.Width(100));
if (GUILayout.Button("選定Target", GUILayout.Width(100)))
{
EditorApplication.delayCall = OnSelectTargetCallback;
}
if (GUILayout.Button("打包AB包", GUILayout.Width(100)))
{
EditorApplication.delayCall = OnBuildAllAB;
}
if (GUILayout.Button("清除AB包", GUILayout.Width(100)))
{
EditorApplication.delayCall = OnCleanAB;
}
EditorGUILayout.Space();
GUILayout.EndHorizontal();
#endregion
GUILayout.BeginHorizontal("box");
GUILayout.Label("包名");
GUILayout.Label("標記", GUILayout.Width(100));
GUILayout.Label("儲存路徑", GUILayout.Width(200));
GUILayout.Label("版本", GUILayout.Width(100));
GUILayout.Label("大小", GUILayout.Width(100));
GUILayout.EndHorizontal();
GUILayout.BeginVertical();
pos = EditorGUILayout.BeginScrollView(pos);
for (int i = 0; i < assetBundleEntities.Count; i++)
{
AssetBundleEntity abe = assetBundleEntities[i];
GUILayout.BeginHorizontal("box");
m_Dict[assetBundleEntities[i].Key] = GUILayout.Toggle(m_Dict[assetBundleEntities[i].Key], abe.Name);
GUILayout.Label(abe.Tag, GUILayout.Width(100));
GUILayout.Label(abe.ToPath, GUILayout.Width(200));
GUILayout.Label(abe.Version.ToString(), GUILayout.Width(100));
GUILayout.Label(abe.Size + "K", GUILayout.Width(100));
GUILayout.EndHorizontal();
foreach (string path in abe.PathList)
{
GUILayout.BeginHorizontal("box");
GUILayout.Space(40);
GUILayout.Label(path);
GUILayout.EndHorizontal();
}
}
EditorGUILayout.EndScrollView();
GUILayout.EndVertical();
}
/// <summary>
/// 清理AssetBundle
/// </summary>
private void OnCleanAB()
{
//開始建立
string toPath = Application.dataPath + "/../AssetBundles/" + arrBuildTarget[buildTargetIndex];
if(Directory.Exists(toPath))
{
Directory.Delete(toPath, true);
Debug.Log("刪除成功");
}
}
/// <summary>
/// 打包AssetBundle
/// </summary>
private void OnBuildAllAB()
{
for (int i = 0; i < assetBundleEntities.Count; i++)
{
if(m_Dict[assetBundleEntities[i].Key])
{
BuildAssetBundle(assetBundleEntities[i]);
}
}
Debug.Log("打包成功");
}
private void BuildAssetBundle(AssetBundleEntity entity)
{
AssetBundleBuild[] arrBuild = new AssetBundleBuild[1];
AssetBundleBuild build = new AssetBundleBuild();
//包名
build.assetBundleName = entity.Name;
//字尾
if (entity.Tag.Equals("scene", StringComparison.CurrentCultureIgnoreCase))
{
build.assetBundleName += ".unity3d";
}
else
{
build.assetBundleName += ".assetbundle";
}
//資源路徑
build.assetNames = entity.PathList.ToArray();
arrBuild[0] = build;
//開始建立
string toPath = Application.dataPath + "/../AssetBundles/" + arrBuildTarget[buildTargetIndex] + entity.ToPath;
if (!Directory.Exists(toPath))
Directory.CreateDirectory(toPath);
BuildPipeline.BuildAssetBundles(toPath, arrBuild, BuildAssetBundleOptions.None, target);
}
/// <summary>
/// 選定Target回撥
/// </summary>
private void OnSelectTargetCallback()
{
//"Windows", "iOS", "Android"
switch (buildTargetIndex)
{
case 0:
target = BuildTarget.StandaloneWindows;
buildTargetIndex = 0;
break;
case 1:
target = BuildTarget.iOS;
buildTargetIndex = 1;
break;
case 2:
target = BuildTarget.Android;
buildTargetIndex = 2;
break;
}
Debug.Log("選定平臺為:" + target.ToString());
}
/// <summary>
/// 選定Tag回撥
/// </summary>
private void OnSelectTagCallback()
{
//"All", "Scene", "Role", "Effect", "Audio", "None"
switch (tagIndex)
{
case 0: //All
foreach (AssetBundleEntity item in assetBundleEntities)
{
m_Dict[item.Key] = true;
}
break;
case 1: //Scene
foreach (AssetBundleEntity item in assetBundleEntities)
{
m_Dict[item.Key] = item.Tag.Equals("scene", StringComparison.CurrentCultureIgnoreCase);
}
break;
case 2: //Role
foreach (AssetBundleEntity item in assetBundleEntities)
{
m_Dict[item.Key] = item.Tag.Equals("role", StringComparison.CurrentCultureIgnoreCase);
}
break;
case 3: //Effect
foreach (AssetBundleEntity item in assetBundleEntities)
{
m_Dict[item.Key] = item.Tag.Equals("effect", StringComparison.CurrentCultureIgnoreCase);
}
break;
case 4: //Audio
foreach (AssetBundleEntity item in assetBundleEntities)
{
m_Dict[item.Key] = item.Tag.Equals("audio", StringComparison.CurrentCultureIgnoreCase);
}
break;
case 5: //None
foreach (AssetBundleEntity item in assetBundleEntities)
{
m_Dict[item.Key] = false;
}
break;
}
}
}
再新建一個類,把AssetBundleWindow例項化出來,就可以看到操作介面了
// CustomMenu.cs
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
public class Menu
{
[MenuItem("MyTools/CreateAssetBundle")]
public static void CreateAssetBundle()
{
AssetBundleWindow abWin = new AssetBundleWindow();
abWin.titleContent = new GUIContent("資源管理");
abWin.Show();
}
}
最終效果圖大概就是這樣:
各類路徑解釋:
PathList:存放的是各類資源在unity中的存放位置
"string toPath = Application.dataPath + "/../AssetBundles/" + arrBuildTarget[buildTargetIndex] + entity.ToPath;"
toPath這個是存放打包的assetbundle的,格式大概為:unity專案上一級目錄/AssetBundles/平臺名(win,Android,ios)/asset型別名/xxx.assetbundle
下一篇我會寫載入AssetBundle,有什麼錯誤或者建議的話,歡迎各位小夥伴留言。