首页 > 其他分享 >AssetBundle打包和读取

AssetBundle打包和读取

时间:2023-09-04 12:00:50浏览次数:46  
标签:读取 private entity GUILayout AssetBundle public 打包 string

基本信息

  创建了项目名有YoyoProject工程,是一个3D模板的工程,使用的是unity 2021版本,windows11系统。

打包

打包路径

string dataPath = Application.dataPath;
string persistentDataPath = Application.persistentDataPath;
string streamingAssetsPath = Application.streamingAssetsPath;
string temporaryCachePath = Application.temporaryCachePath;

Debug.Log("dataPath" + dataPath);
Debug.Log("persistentDataPath" + persistentDataPath);
Debug.Log("streamingAssetsPath" + streamingAssetsPath);
Debug.Log("temporaryCachePath" + temporaryCachePath);
 

打包配置

  定义打包配置,在Editor目录下新建AssetBundle目录,同时创建AssetBundleConfig.xml,内容如下,

<?xml version="1.0" encoding="utf-8" ?>
<Root>
	<AssetBundle>
		<Item Name="Cube" Tag="Wuti" Version="1" Size="0" ToPath="/Wuti/">
			<Path Value="Resources\ItemPrefab\Item\Box\Cube.prefab" >
				
			</Path>
		</Item>

		<Item Name="SampleScene" Tag="Scene" Version="1" Size="0" ToPath="/Scene/">
			<Path Value="Scenes\SampleScene.unity" >

			</Path>
		</Item>

		
	</AssetBundle>
</Root>

  ToPath是表示打包目标路径,

   Path中属性Value是需要打包的资源。

 

新建一个AssetBundleEntity.cs,和Xml中内容对应,代码如下,

public class AssetBundleEntity
{
    public string Key;

    public string Name;
    public string Tag;
    public int Version;
    public long Size;
    public string ToPath;//打包保存的路径

    private List<string> m_PathList = new List<string>();

    public List<string> PathList
    {
        get
        {
            return m_PathList;
        }
    }
}
 

下面是解析XML,将内容放入到AssetBundleEntity类上,GetList()方法就是解析XML的方法,

public class AssetBundleDAL
{
    /// <summary>
    /// XML的路径
    /// </summary>
    private string m_Path;

    /// <summary>
    /// 返回的数据集合
    /// </summary>
    private List<AssetBundleEntity> m_List = null;

    public AssetBundleDAL(string path)
    {
        m_Path = path;
        m_List = new List<AssetBundleEntity>();
    }

    public List<AssetBundleEntity> GetList()
    {
        m_List.Clear();

        //读取XML,把数据添加到m_List中
        XDocument xDoc = XDocument.Load(m_Path);
        XElement root = xDoc.Root;

        XElement assetBundleNode = root.Element("AssetBundle");

        int index  = 0;
        IEnumerable<XElement> lst = assetBundleNode.Elements("Item");
        foreach (XElement item in lst)
        {
            AssetBundleEntity entity = new AssetBundleEntity();
            entity.Key = "Key:"+ ++index;

            //解析 AssetBundle->Item 节点
            entity.Name = item.Attribute("Name").Value;
            entity.Tag = item.Attribute("Tag").Value;
            entity.Version = Int32.Parse(item.Attribute("Version").Value);
            entity.Size = Int64.Parse(item.Attribute("Size").Value);
            entity.ToPath = item.Attribute("ToPath").Value;

            //解析 AssetBundle->Item->Path 节点
            IEnumerable<XElement> pathList = item.Elements("Path");
            foreach (XElement path in pathList)
            {
                entity.PathList.Add(string.Format("Assets/{0}",path.Attribute("Value").Value));
            }
            
            m_List.Add(entity);
        }

        return m_List;
    }
}
  Assets/{0} 中 此处已经统一设置路径前缀为Assets,否则就需要在XML中的Path的Value属性中配置了,所有的资源都是要从Assets目录下开始。   Assets\Resources\ItemPrefab\Item\Box\Cube.prefab  

定制打包界面

  如图所示,编写一个如上所示的打包界面,用于打AssetBundle包。

 

  新建一个AssetBundleWindow.cs类,基础UnityEditor,代码如下,主要是在OnGUI中绘制界面,

/// <summary>
/// AssetBundle管理窗口
/// </summary>
public class AssetBundleWindow : UnityEditor.EditorWindow
{

    private AssetBundleDAL dal;
    private List<AssetBundleEntity> list;

    private Dictionary<string, bool> dic = new Dictionary<string, bool>();

    private string[] arrTag = { "All", "Scene", "Role", "Effect", "Audio", "None" };
    private int tagIndex = 0;

    private string[] arrBuildTarget = { "Windows", "Android", "IOS" };

#if UNITY_STANDALONE_WIN
    private BuildTarget target = BuildTarget.StandaloneWindows;//默认平台
    private int buildTargetIndex = 0;
#elif UNITY_ANDROID
	private BuildTarget target = BuildTarget.Android;
    private int buildTargetIndex = 1;
#elif UNITY_IPHONE
	private BuildTarget target = BuildTarget.iOS;
    private int buildTargetIndex = 2;
#endif


    private string xmlPath;

    private Vector2 pos;

    /// <summary>
    /// 在构造函数AssetBundleWindow后执行
    ///  Application.dataPath 不允许在构造函数中执行
    /// </summary>
    private void OnEnable()
    {
        xmlPath = Application.dataPath + @"\Editor\AssetBundle\AssetBundleConfig.xml";

        dal = new AssetBundleDAL(xmlPath);

        list = dal.GetList();

        for (int i = 0; i < list.Count; i++)
        {
            dic[list[i].Key] = true;
        }
    }

    public AssetBundleWindow()
    {
    }

    /// <summary>
    /// 绘制窗口
    /// </summary>
    private void OnGUI()
    {
        if (list == null) return;

        #region 按钮行
        GUILayout.BeginHorizontal("box");

        tagIndex = EditorGUILayout.Popup(tagIndex, arrTag,GUILayout.Width(100));
        if(GUILayout.Button("选定Tag",GUILayout.Width(100)))
        {
            EditorApplication.delayCall = OnSelctTagCallBack;
        }

        buildTargetIndex = EditorGUILayout.Popup(buildTargetIndex, arrBuildTarget, GUILayout.Width(100));
        if (GUILayout.Button("选定Target", GUILayout.Width(100)))
        {
            EditorApplication.delayCall = OnSelctTargetCallBack;
        }


        if (GUILayout.Button("打AssetBundle包", GUILayout.Width(200)))
        {
            EditorApplication.delayCall = OnAssetBundleCallBack;
        }

        if (GUILayout.Button("清空AssetBundle包", GUILayout.Width(200)))
        {
            //删除打包的资源
            EditorApplication.delayCall = OnClearAssetBundleCallBack;
        }


        GUILayout.EndHorizontal();

        #endregion

        #region 标题行
        GUILayout.BeginHorizontal("box");

        GUILayout.Label("包名");
        GUILayout.Label("标记", GUILayout.Width(100));
        GUILayout.Label("保存路径", GUILayout.Width(100));
        GUILayout.Label("版本", GUILayout.Width(100));
        GUILayout.Label("大小", GUILayout.Width(100));

        GUILayout.EndHorizontal();
        #endregion

        #region 内容区域
        GUILayout.BeginVertical();

        pos = EditorGUILayout.BeginScrollView(pos);//添加滚动区域

        for(int i = 0; i < list.Count; i++)
        {
            AssetBundleEntity entity = list[i];
            GUILayout.BeginHorizontal("box");

            dic[entity.Key] = GUILayout.Toggle(dic[entity.Key], "",GUILayout.Width(20));//复选框

            GUILayout.Label(entity.Name);
            GUILayout.Label(entity.Tag, GUILayout.Width(100));
            GUILayout.Label(entity.ToPath, GUILayout.Width(100));
            GUILayout.Label(entity.Version.ToString(), GUILayout.Width(100));
            GUILayout.Label(entity.Size.ToString(), GUILayout.Width(100));

            GUILayout.EndHorizontal();

            foreach(string path in entity.PathList)
            {
                GUILayout.BeginHorizontal("box");

                GUILayout.Space(40);//添加空格
                GUILayout.Label(path);


                GUILayout.EndHorizontal();
            }

        }

        EditorGUILayout.EndScrollView();

        GUILayout.EndVertical();
        #endregion
    }

    /// <summary>
    /// 选定Tag回调
    /// </summary>
    /// <exception cref="NotImplementedException"></exception>
    private void OnSelctTagCallBack()
    {
    }

    private void OnSelctTargetCallBack()
    {

    }
    private void OnAssetBundleCallBack() { }

    private void OnClearAssetBundleCallBack() { }
}

 

  在Menu.cs中,让窗口展示出来,

public class Menu : MonoBehaviour
{
    [MenuItem("CustomTools/AssetBundleCreate")]
   public static void AssetBundleCreate()
    {
        AssetBundleWindow win = EditorWindow.GetWindow<AssetBundleWindow>();
        win.titleContent = new GUIContent("AssetBundle打包");
        win.Show();
    }
}

 

回调代码

 /// <summary>
/// 选定Tag回调
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void OnSelctTagCallBack()
{
    switch (tagIndex)
    {
        case 0://All
            foreach (AssetBundleEntity entity in list)
            {
                dic[entity.Key] = true;
            }
            break;
        case 1://Scene
            foreach (AssetBundleEntity entity in list)
            {
                dic[entity.Key] = entity.Tag.Equals("Scene", StringComparison.CurrentCultureIgnoreCase);
            }
            break;
        //其他同Scene
        case 5://None
            foreach (AssetBundleEntity entity in list)
            {
                dic[entity.Key] = false;
            }
            break;
    }
}

private void OnSelctTargetCallBack()
{
    switch (buildTargetIndex)
    {
        case 0://Windows
            target = BuildTarget.StandaloneWindows;
            break;
        case 1://Android
            target = BuildTarget.Android;
            break;
        case 2://IOS
            target = BuildTarget.iOS;
            break;
    }
}

 

打包代码(仅参考)

  主要是调用 BuildPipeline.BuildAssetBundles,

/// <summary>
/// 打AssetBundle包的回调
/// </summary>
private void OnAssetBundleCallBack() { 
    //被选中需要打包的资源
    List<AssetBundleEntity> listNeedBuild = new List<AssetBundleEntity>();   

    foreach (AssetBundleEntity entity in list)
    {
        if (dic[entity.Key])
        {
            listNeedBuild.Add(entity); 
        }
    }

    //循环打包
    for(int i=0; i<listNeedBuild.Count; i++)
    {
        BuildAssetBundle(listNeedBuild[i]);
    }
    Debug.Log("打包完成");

}

private void BuildAssetBundle(AssetBundleEntity entity)
{
    AssetBundleBuild[] arrBuild = new AssetBundleBuild[1];

    AssetBundleBuild build = new AssetBundleBuild();

    //后缀
    string suffix = (entity.Tag.Equals("Scene", StringComparison.CurrentCultureIgnoreCase) ? "unity3d" : "assetbundle");

    //包名
    build.assetBundleName = string.Format("{0}.{1}",entity.Name,suffix);

    //资源路径
    build.assetNames = entity.PathList.ToArray();

    arrBuild[0] = build;

    //包存放路径
    //dataPath路径为: E:\workspace\unity_workspace\YoyoProject\Assets  想放到,E:\workspace\unity_workspace\YoyoProject\AssetBundles目录下
    //AssetBundles目录是自己建的
    string toPath = Application.dataPath + "/../AssetBundles/" + arrBuildTarget[buildTargetIndex]+entity.ToPath;

    if (!System.IO.Directory.Exists(toPath))//创建目录
    {
        Directory.CreateDirectory(toPath);
    }

    //打包
    BuildPipeline.BuildAssetBundles(toPath, arrBuild, BuildAssetBundleOptions.None, target);

}

 

  上面打包代码执行报错,

 

 

  报错原因是我在Camera挂载的脚本下引用了UnityEditor,这两个是无法被打包进可执行程序的,

using UnityEditor;
using UnityEditor.Build;

 

  如下图打包成功后,

 

清空包

  /// <summary>
/// 清空打的AssetBundle包
/// </summary>
private void OnClearAssetBundleCallBack() {

    string path = Application.dataPath + "/../AssetBundles/" + arrBuildTarget[buildTargetIndex];
    if(Directory.Exists(path))
    {
        Directory.Delete(path, true);//第二个参数表示,级联删除数据
    }
}

 

读取

读取AssetBundle

  新建LocalFileMgr文件在Scripts目录下,代码如下,主要是读取本地资源文件,

/// <summary>
/// 本地文件管理
/// </summary>
public class LocalFileMgr : Singleton<LocalFileMgr>
{
#if UNITY_STANDALONE_WIN
    private static string platform = "Windows";
#elif UNITY_IPHONE
    private static string platform = "IOS";
#elif UNITY_ANDROID
    private static string platform = "Android";
#endif

#if UNITY_EDITOR
    public readonly string LocalFilePath = Application.dataPath + "/../AssetBundles/"+ platform;
#elif UNITY_ANDROID || UNITY_IPHONE || UNITY_STANDALONE_WIN
    public readonly string LocalFilePath = Application.persistentDataPath + "/";
#endif

    public byte[] GetBuffer(string path)
    {
        byte[] buffer = null;

        using(FileStream fs = new FileStream(path, FileMode.Open))
        {
            buffer = new byte[fs.Length];
            fs.Read(buffer, 0, buffer.Length);
        }

        return buffer;
    }
}

 

同步加载

  当要获取实例时,如下,这样就从资源包里面获取到预制体等资源,

  运行后会在界面展示一个方块,

byte[] buffer = LocalFileMgr.Instance.GetBuffer(@"E:\workspace\unity_workspace\YoyoProject\AssetBundles\Windows\Wuti\cube.assetbundle");

AssetBundle bundle = AssetBundle.LoadFromMemory(buffer);

//加载镜像
GameObject obj = bundle.LoadAsset("Cube") as GameObject;

//卸载bundler
bundle.Unload(false);

Instantiate(obj);

   上述加载方式是同步加载,如果这个资源很大,那么就需要异步加载。

 

异步加载

  编写异步加载的类AssetBundleLoaderAsync,代码如下,其中有一个回调方法——OnLoadComplete,当加载完毕后执行。

  异步加载主要是用到协程和AssetBundle.LoadFromMemoryAsync。

public class AssetBundleLoaderAsync : MonoBehaviour
{
    private string m_FullPath;
    private string m_Name;

    private AssetBundle m_Bundle;
    private AssetBundleCreateRequest request;


    public Action<UnityEngine.Object> onl oadComplete;

    public void init(string path,string name)
    {
        m_FullPath = LocalFileMgr.Instance.LocalFilePath+"/"+ path;
        m_Name = name;
    }

    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(Load());
    }

    private IEnumerator Load()
    {
        request = AssetBundle.LoadFromMemoryAsync(LocalFileMgr.Instance.GetBuffer(m_FullPath));
        yield return request;

        m_Bundle = request.assetBundle;

        if(OnLoadComplete != null)
        {
            onl oadComplete(m_Bundle.LoadAsset(m_Name));
            Destroy(gameObject);
        }
    }

    private void OnDestroy()
    {
        if (m_Bundle != null) m_Bundle.Unload(false);

        m_FullPath =null;
        m_Name =null;
    }
}

 

  测试异步加载,

public AssetBundleLoaderAsync LoadAsync(string path,string name)
{
    GameObject obj = new GameObject("AssetBundleCreate");
    AssetBundleLoaderAsync async = obj.GetOrAddComponent<AssetBundleLoaderAsync>();

    async.init(path, name);

    return async;
}
void Start()
{
    AssetBundleLoaderAsync async = LoadAsync(@"Wuti\cube.assetbundle", "cube");
    async.OnLoadComplete = onl oadComplete;

}

private void onl oadComplete(UnityEngine.Object obj)
{
    Instantiate(obj);
}

 

  最终和同步一样,出现一个方块,

 

标签:读取,private,entity,GUILayout,AssetBundle,public,打包,string
From: https://www.cnblogs.com/weiyanei/p/17676552.html

相关文章

  • python 创建、读取xml 文件
    使用xml.dom.minidom1.创建fromxml.dom.minidomimportDocument#创建xml文件doc=Document()#创建根节点root_node=doc.createElement("root")doc.appendChild(root_node)#创建子节点son_node=doc.createElement("son_node")root_node.appendChild(son......
  • C#读取XSL文件将XML内容转化为指定XML内容
    //加载xsl样式表文件XslCompiledTransformxslt=newXslCompiledTransform();xslt.Load("path/to/your/xsl/file.xsl");//加载XML文件XmlDocumentxmlDoc=newXmlDocument();xmlDoc.Load("path/to/your/xml/file.xml");//......
  • GraalVM 打包 Java ShellcodeLoader 为可执行文件
    GraalVM打包JavaShellcodeLoader为可执行文件url:https://app.yinxiang.com/fx/a6667249-7c5e-40dd-8bf6-e474fc844163title:GraalVM打包JavaShellcodeLoader为可执行文件date:2023-03-0212:37:26打包成Jar包先上项目地址:https://github.com/yzddmr6/Java-Sh......
  • maven打包提示“-source1.5中不支持diamond运算符终极解决办法”
    把所有能设置Java的地方都改过来了,还是不行,最后在Maven的setting.xml中设置了一下Jdk好使了<profiles><profile><id>jdk1.8</id><activation><activeByDefault>true</activeByDefault><jdk......
  • 实现python自动化进行薪资核算——数据读取、数据计算、数据输出
    前言上一篇文章我们完成了相关准备工作——pandas库的安装以及相关库问题的解决,这篇文章实现简单的薪资核算工作。功能要求当前表格中,考勤扣除金额、个税扣除、实发工资目前是空缺的,最终生成的数据需要将上述三列的数据分别根据以下规则填充。1、迟到次数核算方法:3次以内不扣除3次......
  • 如何将项目打包上传到NuGet服务器?
    作者:西瓜程序猿主页传送门:https://www.cnblogs.com/kimiliucn前言在我写[在.NETFramework中使用RocketMQ(阿里云版)]这篇博客的时候,因为封装了很多代码在单独的DLL中,包括生产者、消费者以及官方SDK等等,然后都在博客中体现出来导致博客大量代码,然后有位读者就建议打包成NuG......
  • Python顺序读取word文档中的文本与表格
    importosimportdocxfromdocx.documentimportDocumentfromdocx.oxml.tableimportCT_Tblfromdocx.oxml.text.paragraphimportCT_Pfromdocx.tableimport_Cell,Tablefromdocx.text.paragraphimportParagraphdefiter_block_items(parent):"......
  • python办公自动化(6)——读取word文档
     #使用import导入os模块importos#将乔老师的答题卡文件夹路径/Users/qiao/answerKey赋值给变量allKeyPathallKeyPath="/Users/qiao/answerKey"#使用os.listdir()函数获取该路径下所有的文件,并赋值给变量allItemsallItems=os.listdir(allKeyPath)#定义一个......
  • C语言读取csv文件并保存到二维数组
     #include<stdio.h>#include<string.h>#include<time.h>#defineMAXCHAR1024#defineMAXCOUNT1000000char*mat[MAXCOUNT][9];//如果放到main里面会有长度限制使应用程序退出,放在外面作为全局变量没有限制。intmain(){clock_tstart,end;start=clo......
  • JavaFX+SpringBoot桌面项目并打包成exe可执行文件
    1.创建标准Maven工程2.引入依赖<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation=&quo......