欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

AssetBundle打包步骤超级详解

程序员文章站 2022-06-28 15:29:14
(一)ab是什么,打包流程简述ab是一种资源的加载方式,是一种压缩文件的格式为什么需要ab?如果一个游戏的所有资源都打包成一整个资源,那游戏包会很大,如果是每个关卡的资源,每个关卡的加载,包会小点,所以ab就是把各种类型的资源如音乐,图片,场景,音效等变成一个ab包放到服务器上,然后客户端联网后,从服务器上下载,在本地动态加载资源,以达到资源更新的目的ps:更新有资源热更和代码热更,代码热更需要通过c#+xlua框架的方式(二)打包步骤1.设置打包对象2.生成ab包3.上传到服务器4.加载...

(一)ab是什么,打包流程简述
ab是一种资源的加载方式,是一种压缩文件的格式
为什么需要ab?
如果一个游戏的所有资源都打包成一整个资源,那游戏包会很大,如果是每个关卡的资源,每个关卡的加载,包会小点,所以ab就是把各种类型的资源如音乐,图片,场景,音效等变成一个ab包放到服务器上,然后客户端联网后,从服务器上下载,在本地动态加载资源,以达到资源更新的目的
ps:更新有资源热更和代码热更,代码热更需要通过c#+xlua框架的方式
(二)打包步骤
1.设置打包对象
2.生成ab包
3.上传到服务器
4.加载ab包中的资源
5.使用ab包中的资源
(三)步骤一:设置打包对象
AssetBundle打包步骤超级详解
这里的assetbundle是打包的包名,后面的那个none是扩展名
即可以给这个方块资源设置成包名为fangkuai,扩展名为u3d
(四)用代码生成ab包
1.assets下新建一个Editor文件夹,因为打包是在编辑下进行的。
2.在这个Editor文件夹下建立一个脚本,脚本在编辑状态下,所以不继承monobehaviour,继承Editor,且引入命名空间using UnityEditor;
注意:不要运行unity点击按钮打包,直接等编译完,点击按钮就可以了。

using UnityEditor;
using System.IO;//创建文件夹要用的包

public class MyTools
{
    [MenuItem("Tools/CreateAssetBundles")]//在uinty上建一个菜单Tools下有个CreateBundles的菜单

    static void CreateAssetBundles()//这是点击这个按钮的功能
    {
        
        //打包的路径
        string assetBundleDirectory = "StreamingAssets";
        //如果没有就在工程下创建一个这样的路径
        if (!Directory.Exists(assetBundleDirectory))
        {
            Directory.CreateDirectory(assetBundleDirectory);
        }
        //打包资源:参数解析:assetBundleDirectory:打包到哪里,目录
        //BuildAssetBundleOptions:none默认的打包方式
        //BuildTarget:打包的平台
        BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, BuildTarget.StandaloneOSX);

        UnityEngine.Debug.Log("打包完成");
    }

    
   
}

编译完打包出来的目录是这样的
AssetBundle打包步骤超级详解
点开streamingAssets是这样的资源清单和一些依赖关系
AssetBundle打包步骤超级详解
如何打包归类:
1.每种类型打个包
2.或者一个界面,关卡的资源打个包。

打包要注意的:
如果不把模型用的mat.u3d打包,而是把这三个预置体打包,那么这三个预置体中的材质都会被打包一次,每个预制体大概是20多kb,如果是把mat.u3d打包了,每个预制体的材质也相当于打包了,每个预制体是几kb。

(五)读取assetbundle的四种方式(内存,文件,www,unitywebrequest)
建立一个脚本,将脚本绑定到空对象上
注意:加载都用协程
(1)从内存中加载ab包中的单个资源

public class LoadAssetBundle : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(LoadFromMemory());
    }

    //从内存读取ab包
    IEnumerator LoadFromMemory()
    {
        //要找的ab包里的资源的路径
        string boxPath = @"Desktop/LittleSomethingsTest/StreamingAssets/box.u3d";
        string matPath = @"Desktop/LittleSomethingsTest/StreamingAssets/mat.u3d";
        //把资源读取成byte[]
        byte[] boxBytes = File.ReadAllBytes(boxPath);
        byte[] matBytes= File.ReadAllBytes(matPath);
        //加载ab包
        AssetBundle boxAB = AssetBundle.LoadFromMemory(boxBytes);
        AssetBundle matAB = AssetBundle.LoadFromMemory(matBytes);
        //取出ab包里的资源,名字不是打包的名字,是从捆绑包中加载名为 name 的资源,原始的名字
        GameObject boxPrefab = boxAB.LoadAsset<GameObject>("Cube");
        //实例化资源
        Instantiate(boxPrefab);
        yield return null;

    }
}

注意:这里因为事材质也分别打了包,所以加载ab包时,不能光加载模型,而是要把模型的材质也加载进来,不然模型丢失材质会变粉。
(2)从文件中加载ab包中的单个资源

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class LoadAssetBundle : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine(LoadFromFile());
    }

    //从单个文件中读取ab包
    IEnumerator LoadFromFile()
    {
        //要找的ab包里的资源的路径,材质也要加载
        string boxPath = @"Desktop/LittleSomethingsTest/StreamingAssets/box.u3d";
        string matPath = @"Desktop/LittleSomethingsTest/StreamingAssets/mat.u3d";
        //加载资源包和材质包
        AssetBundle boxAB = AssetBundle.LoadFromFile(boxPath);
        AssetBundle matAB = AssetBundle.LoadFromFile(matPath);
        //取出ab包的资源实例化
        GameObject boxPrefab = boxAB.LoadAsset<GameObject>("cube");
        Instantiate(boxPrefab);
        yield return null;
    }
}

(3)将多个资源打入一个ab包,然后从文件读取ab包中的多个资源

1.把要打包的模型设置成同一个包名allobjects,扩展名都是u3d,材质单独一个包名mat
如图所示
AssetBundle打包步骤超级详解
2.代码实现

//从文件中读取ab包中的多个资源对象
    IEnumerator AllFromFile()
    {
        //要加载的ab包路径
        string prefabsPath = @"Desktop/LittleSomethingsTest/StreamingAssets/allobjects.u3d";
        string matPath = @"Desktop/LittleSomethingsTest/StreamingAssets/mat.u3d";
        //从文件加载ab包
        AssetBundle prefabsAB = AssetBundle.LoadFromFile(prefabsPath);
        AssetBundle matAB = AssetBundle.LoadFromFile(matPath);
        //从ab包中加载所有资源
        Object[] objList = prefabsAB.LoadAllAssets();
        //遍历这些资源,然后实例化
        foreach(var go in objList)
        {
            Debug.Log(((GameObject)go).name);
            Instantiate(((GameObject)go));
        }
        yield return null;
    }

(4)www方式无缓存机制的加载ab包的方式
www有两种方式,本地和http的,下面是本地方式

//用www的方式无缓存机制本地加载ab包中的资源
    IEnumerator FromWWW1()
    {
        //资源的www
        string prefabsPath = @"file:///Desktop/LittleSomethingsTest/StreamingAssets/allobjects.u3d";
        WWW prefabsWWW = new WWW(prefabsPath);
        yield return prefabsWWW;//等www加载完,似乎这句不加也不影响加载?
        if (!string.IsNullOrEmpty(prefabsWWW.error))//如果加载有错就输出错误
        {
            Debug.Log("加载错误" + prefabsWWW.error);
        }
        //使用加载出来的ab包
        AssetBundle prefabsAB = prefabsWWW.assetBundle;
        Object[] objList = prefabsAB.LoadAllAssets();
        foreach(var go in objList)
        {
            Instantiate(((GameObject)go));
        }

        //材质的www
        string matPath = @"file:///Desktop/LittleSomethingsTest/StreamingAssets/mat.u3d";
        WWW matWWW = new WWW(matPath);
        //yield return matWWW;//注意如果这里加了这句,加载场景的时候prefab会先变粉再变成有材质的颜色,这是为什么呢……
        AssetBundle matAB = matWWW.assetBundle;//这里别忘了材质的ab包
        yield return null;
    }

(5)带有缓存机制的www

 //有缓存机制的www方式加载ab包:即当缓存有时用缓存里的ab包,缓存没有时,再去地址下载ab包
    IEnumerator FromWWWHC()
    {
        string prefabsPath = @"file:///Desktop/LittleSomethingsTest/StreamingAssets/allobjects.u3d";
        //参数解析:第一个是下载ab包的路径,第二个是哈希数值用来识别版本号,当要求加载的路径和版本号都对上时,从缓存中加载,即版本号用来识别是缓存里的ab包的哪一个下载了的版本。
        WWW prefabsWWW = WWW.LoadFromCacheOrDownload(prefabsPath, 1);
        if (!string.IsNullOrEmpty(prefabsWWW.error))//如果加载有错就输出错误
        {
            Debug.Log("加载错误" + prefabsWWW.error);
            yield break;
        }
        AssetBundle prefabsAB = prefabsWWW.assetBundle;
        Object[] objList = prefabsAB.LoadAllAssets();
        foreach (var go in objList)
        {
            Instantiate(((GameObject)go));
        }

        //材质的ab包
        string matPath = @"file:///Desktop/LittleSomethingsTest/StreamingAssets/mat.u3d";
        WWW matWWW = WWW.LoadFromCacheOrDownload(matPath, 1);
        AssetBundle matAB = matWWW.assetBundle;

        yield return null;
    }

ps:www对象还可以释放,通过添加
prefabsWWW.Dispose();
prefabsWWW = null;
(6)用unityWebRequest方式(新版本)
引入命名空间:using UnityEngine.Networking;

//用uintyWebRequest加载ab包
    IEnumerator FromUnityWebRequest()
    {
        string prefabsPath = @"file:///Desktop/LittleSomethingsTest/StreamingAssets/allobjects.u3d";
        UnityWebRequest prefabsRequest;
        prefabsRequest = UnityWebRequestAssetBundle.GetAssetBundle(prefabsPath);//命令从这个路径获取ab包
        yield return prefabsRequest.SendWebRequest();//命令之后,还要发送这个命令
        //api注释调用此方法后,UnityWebRequest 将执行 DNS 解析(如有必要),将一个 HTTP 请求传输到位于目标 URL 的远程服务器,并处理该服务器的响应。
        //在任何给定的 UnityWebRequest 对象上,此方法只能调用一次。
        AssetBundle prefabsAB = DownloadHandlerAssetBundle.GetContent(prefabsRequest);//从unitywebrequest中的对象获取内容
        Object[] objList = prefabsAB.LoadAllAssets();
        foreach (var go in objList)
        {
            Instantiate(((GameObject)go));
        }

        //读取资源
        string matPath = @"file:///Desktop/LittleSomethingsTest/StreamingAssets/mat.u3d";
        UnityWebRequest matRequest;
        matRequest = UnityWebRequestAssetBundle.GetAssetBundle(matPath);
        yield return matRequest.SendWebRequest();//如果把这个注释掉,这个matrequest就是个未完成的请求对象,后面材质获取不到
        AssetBundle matAB = DownloadHandlerAssetBundle.GetContent(matRequest);
        yield return null;
    }

ps:这种写法会预制体先试粉的,然后有材质,所以,可以让材质在预制体之前加载就可以了。写的顺序换一下。

(7)从文件通过主manifest文件加载所有的ab包

//以文件方式为例,通过主manifest文件加载所有资源和所有依赖项
    IEnumerator LoadAssetsFromManifest()
    {
        string manifestPath = @"Desktop/LittleSomethingsTest/StreamingAssets/StreamingAssets";
        AssetBundle manifestAB = AssetBundle.LoadFromFile(manifestPath);
        //注意这里manifest的名字不是文件夹中的StreamingAssets名字,而是固定的AssetBundleManifest
        AssetBundleManifest manifest = manifestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        // manifest.GetAllAssetBundles()这个获得的是个string[],是所有ab包的名字及其扩展名的一个字符串数组
        foreach(string str in manifest.GetAllAssetBundles())
        {
            string abPath = @"Desktop/LittleSomethingsTest/StreamingAssets/" + str;
            AssetBundle ab = AssetBundle.LoadFromFile(abPath);//每一个ab包中可能有多个资源,遍历然后实例化
            object[] objList = ab.LoadAllAssets();
            foreach(var go in objList)//因为这里是所有的ab包,其中也包含了不是游戏物体的材质,所以这里要判断一下,是材质才创建实例
            {
                //因为这里是所有的ab包,其中也包含了不是游戏物体的材质,所以这里要判断一下,是材质才创建实例
                //不然转换会报错
                if (go is GameObject)
                {
                    Instantiate(((GameObject)go));
                }
                
            }

            
        }

        yield return null;
    }

(8)从文件,通过主manifest加载特定ab包的依赖项

//以文件方式为例,通过主manifest文件获取特定ab包的依赖
    IEnumerator LoadDependenciesFromManifest()
    {
        string prefabsPath = @"Desktop/LittleSomethingsTest/StreamingAssets/allobjects.u3d";
        AssetBundle prefabsAB = AssetBundle.LoadFromFile(prefabsPath);
        Object[] objList = prefabsAB.LoadAllAssets();
        foreach(var go in objList)
        {
            Debug.Log(((GameObject)go).name);
            Instantiate(((GameObject)go));
        }
        //上面这几行代码是加载了ab包中的预制体,但是因为没有加载其依赖项,所以都是粉色的
        //下面通过主manifest添加资源的依赖项
        string manifestPath = @"Desktop/LittleSomethingsTest/StreamingAssets/StreamingAssets";
        AssetBundle manifestAB = AssetBundle.LoadFromFile(manifestPath);
        AssetBundleManifest manifest = manifestAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
        string[] strs = manifest.GetAllDependencies("allobjects.u3d");//得到这个包的所有依赖项的名字的字符串数组
        //加载依赖项的ab包
        foreach(string s in strs)
        {
            AssetBundle.LoadFromFile(@"/Users/Magician/Desktop/LittleSomethingsTest/StreamingAssets/"+s);
        }


        yield return null;
    }

(9)服务器上加载ab包同理,改路径为地址就行

本文地址:https://blog.csdn.net/qq_42385019/article/details/107320383