Unity笔记之AssetBundle打包和加载(场景和预制体)
需求:实现用AssetBundle打包和加载场景、预制体。
这是参照一位大佬的拿来改了一点,但是现在没找到大佬的文章,就先这样吧。
实现打AB包方法一:
打包工具AssetBundleBuilder.cs
using UnityEngine;
using UnityEditor;
using System.IO;
/// <summary>
/// 资源包打包工具
/// </summary>
public class AssetBundleBuilder : EditorWindow
{
[MenuItem("打包/Windows/资源包和场景")]
public static void BuildAbsAndScenesWindows()
{
AssetBundleBuilder assetBundleBuilder = EditorWindow.GetWindow<AssetBundleBuilder>();
assetBundleBuilder.Show();
//
}
static string outPath;
private void OnGUI()
{
GUILayout.Space(10);
GUI.skin.label.fontSize = 12;
GUI.skin.label.alignment = TextAnchor.MiddleLeft;
GUILayout.Label("AssetBundle文件名称:", GUILayout.MaxWidth(160));
outPath = EditorGUILayout.TextField(outPath);
EditorGUI.EndDisabledGroup();
//string s = EditorGUILayout.TextArea("s");
if (GUILayout.Button("开始打包场景和资源"))
{
BuildAbsAndScenes(BuildTarget.StandaloneWindows);
}
//GUILayout.EndVertical();
//EndWindows();
}
[MenuItem("打包/Android/资源包和场景")]
public static void BuildAbsAndScenesAndroid()
{
BuildAbsAndScenes(BuildTarget.Android);
}
[MenuItem("打包/IOS/资源包和场景")]
public static void BuildAbsAndScenesIOS()
{
BuildAbsAndScenes(BuildTarget.iOS);
}
[MenuItem("打包/Windows/资源包")]
public static void BuildAbsWindows()
{
BuildAssetBundles(BuildTarget.StandaloneWindows);
}
[MenuItem("打包/Android/资源包")]
public static void BuildAbsAndroid()
{
BuildAssetBundles(BuildTarget.Android);
}
[MenuItem("打包/IOS/资源包")]
public static void BuildAbsIOS()
{
BuildAssetBundles(BuildTarget.iOS);
}
[MenuItem("打包/Windows/场景")]
public static void BuildScenesWindows()
{
BuildScenes(BuildTarget.StandaloneWindows);
}
[MenuItem("打包/Android/场景")]
public static void BuildScenesAndroid()
{
BuildScenes(BuildTarget.Android);
}
[MenuItem("打包/IOS/场景")]
public static void BuildScenesIOS()
{
BuildScenes(BuildTarget.iOS);
}
// 打包AssetBundle和Scenes
public static void BuildAbsAndScenes(BuildTarget platform)
{
BuildAssetBundles(platform);
BuildScenes(platform);
}
// 打包AssetBundles
private static void BuildAssetBundles(BuildTarget platform)
{
// 输出路径
//string outPath = Application.streamingAssetsPath + "/Abs";
if (!Directory.Exists(outPath)) Directory.CreateDirectory(outPath);
EditorUtility.DisplayProgressBar("信息", "打包资源包", 0f);
BuildPipeline.BuildAssetBundles(outPath, BuildAssetBundleOptions.DeterministicAssetBundle, platform);
AssetDatabase.Refresh();
Debug.Log("所有资源包打包完毕");
}
// 打包Scenes
private static void BuildScenes(BuildTarget platform)
{
// 指定场景文件夹和输出路径
string scenePath = Application.dataPath + "/AbResources/Scenes";
//string outPath = Application.streamingAssetsPath + "/Abs/";
if (Directory.Exists(scenePath))
{
// 创建输出文件夹
if (!Directory.Exists(outPath)) Directory.CreateDirectory(outPath);
// 查找指定目录下的场景文件
string[] scenes = GetAllFiles(scenePath, "*.unity");
for (int i = 0; i < scenes.Length; i++)
{
string url = scenes[i].Replace("\\", "/");
int index = url.LastIndexOf("/");
string scene = url.Substring(index + 1, url.Length - index - 1);
string msg = string.Format("打包场景{0}", scene);
EditorUtility.DisplayProgressBar("信息", msg, 0f);
scene = scene.Replace(".unity", ".scene");
Debug.Log(string.Format("打包场景{0}到{1}", url, outPath + scene));
BuildPipeline.BuildPlayer(scenes, outPath + scene, BuildTarget.StandaloneWindows, BuildOptions.BuildAdditionalStreamedScenes);
AssetDatabase.Refresh();
}
EditorUtility.ClearProgressBar();
Debug.Log("所有场景打包完毕");
}
}
/// <summary> 获取文件夹和子文件夹下所有指定类型文件 </summary>
private static string[] GetAllFiles(string directory, params string[] types)
{
if (!Directory.Exists(directory)) return new string[0];
string searchTypes = (types == null || types.Length == 0) ? "*.*" : string.Join("|", types);
string[] names = Directory.GetFiles(directory, searchTypes, SearchOption.AllDirectories);
return names;
}
}
加载ABTest.cs
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class ABTest : MonoBehaviour
{
public Text textProgress;
private void Awake()
{
//DontDestroyOnLoad(gameObject);
//StartCoroutine(DownloadPrefab());
//StartCoroutine(DownloadScene());
LoadScene(Application.streamingAssetsPath + "/Abs/" + "test");
LoadPrefabs(Application.streamingAssetsPath + "/Abs/" + "cube.ab");
}
public void LoadPrefabs(string url)
{
StartCoroutine(DownloadPrefab(url));
}
IEnumerator DownloadPrefab(string url)
{
//ab包的地址
//string url = Application.streamingAssetsPath + "/Abs/" + "cube" + ".ab";
AssetBundle ab;
using (UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url))
{
//yield return request.SendWebRequest();
request.SendWebRequest();
while (!request.isDone)
{
Debug.Log(request.downloadProgress);
//textProgress.text = (request.downloadProgress * 100).ToString("F0") + "%";
yield return null;
}
if (request.isDone)
{
Debug.Log(100);
//textProgress.text = 100 + "%";
}
ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
if (ab == null)
{
Debug.LogError("AB包为空");
yield break;
}
}
GameObject ga = ab.LoadAsset<GameObject>("Assets/Prefabs/cube.prefab");//加载出来
Instantiate<GameObject>(ga);//实例化出来
//Debug.Log(ga.name);
//ab.Unload(false);
Debug.Log("成功");
yield break;
}
public void LoadScene(string url)
{
StartCoroutine(DownloadScene(url));
}
IEnumerator DownloadScene(string url)
{
//ab包的地址
//string url = Application.streamingAssetsPath + "/Abs/" + "samplescene";
//方式一
//AssetBundle ab;
//using (UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(url))
//{
// //yield return request.SendWebRequest();
// request.SendWebRequest();
// while (!request.isDone)
// {
// Debug.Log(request.downloadProgress);
// //textProgress.text = (request.downloadProgress * 100).ToString("F0") + "%";
// yield return null;
// }
// if (request.isDone)
// {
// Debug.Log(100);
// //textProgress.text = 100 + "%";
// }
// ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
// if (ab == null)
// {
// Debug.LogError("AB包为空");
// yield break;
// }
// string[] s = ab.GetAllScenePaths();
// SceneManager.LoadScene(s[0], LoadSceneMode.Single);
//}
//方式二
myLoadedAssetBundle = AssetBundle.LoadFromFile(url);
scenePaths = myLoadedAssetBundle.GetAllScenePaths();
SceneManager.LoadScene(scenePaths[0], LoadSceneMode.Single);
Debug.Log("成功");
yield break;
}
private AssetBundle myLoadedAssetBundle;
private string[] scenePaths;
}
这里面的加载场景有两种方式,但是最关键、核心的就是这句代码
scenePaths = myLoadedAssetBundle.GetAllScenePaths();
以上就是打包和加载了
但是这样的打包存在一定的局限性,不太建议使用这种方式。还有一种方式就是使用官方的AssetBundleBrowser来进行打包和加载(也是个人比较推荐的)。
实现打AB包方法二:
1、去PackageManager里面下载Asset Bundle Browser;
2、打开Asset Bundle Browser窗口;
3、把资源拖进去
(这里报感叹号弄成依赖资源就可以去掉了,当然也可以不管)
然后build根据个人需求修改就可以打包了
至此,打包结束。
然后就是加载资源:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
public class DemoLoadBundle : MonoBehaviour
{
public string bundleName = "dogpbr";//预制体ab的名字
public string assetName = "dogpbr";//加载到场景中这个物体的名字
private void Start()
{
DontDestroyOnLoad(gameObject);
LoadDependencies();
LoadBundleScene();
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Q))
{
InstantiateBundlePrefab();
}
}
/// <summary>
/// 保存所有AssetBundle包的物体的名字
/// </summary>
public List<string> abPrefabNameList = new List<string>();
/// <summary>
/// 保存所有AssetBundle包场景的名字
/// </summary>
public List<string> abSceneNameList = new List<string>();
/// <summary>
/// 加载所有依赖资源(这里记录的只是单个场景和单个预制体的演示)
/// </summary>
void LoadDependencies()
{
//AssetBundleManifest 记录着所有资源的依赖信息
AssetBundle assetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/StandaloneWindows");
AssetBundleManifest manifest = assetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");
//获取所有ab资源的名字
string[] s = manifest.GetAllAssetBundles();
for (int i = 0; i < s.Length; i++)
{
if (Check(s[i])||s[i].Contains("new")) continue;
if (s[i].Contains("scene")) abSceneNameList.Add(s[i]);
else abPrefabNameList.Add(s[i]);
Debug.Log(s[i]);
}
//加载预制体的依赖包
string[] dependenciesPrefab = manifest.GetAllDependencies(bundleName);
foreach (var dependencie in dependenciesPrefab)
{
var dependencieAsync = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + dependencie);
}
//加载场景的依赖包
string[] dependencieScene = manifest.GetAllDependencies(sceneName);
foreach (var dependencie in dependencieScene)
{
var dependencieAsync = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + dependencie);
}
}
private bool Check(string name)
{
if (abPrefabNameList.Contains(name)) return true;
if (abSceneNameList.Contains(name)) return true;
return false;
}
AssetBundle asset;//实现可多次加载
/// <summary>
/// 加载ab包的预制体(单个)
/// </summary>
private void InstantiateBundlePrefab()
{
if (asset == null)
asset = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + bundleName);
var asset_go = asset.LoadAsset<GameObject>(assetName);
Instantiate(asset_go);
}
public string sceneName = "abtestscene";//场景打包出来的名字
#region 方式一
/// <summary>
/// 加载ab包的场景(单个)
/// 注:加载场景的时候可能会出现一个问题,那就是场景里面存在一个ab包的预制体,但你再去加载这个预制体就会报错。(解决办法就是把你场景里面的那个预制体删掉就可以了)
/// </summary>
IEnumerator LoadABScene()
{
AssetBundle ab;
using (UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(""))
{
//yield return request.SendWebRequest();
request.SendWebRequest();
while (!request.isDone)
{
Debug.Log(request.downloadProgress);
//textProgress.text = (request.downloadProgress * 100).ToString("F0") + "%";
yield return null;
}
if (request.isDone)
{
Debug.Log(100);
//textProgress.text = 100 + "%";
}
ab = (request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;
if (ab == null)
{
Debug.LogError("AB包为空");
yield break;
}
string[] s = ab.GetAllScenePaths();
SceneManager.LoadScene(s[0], LoadSceneMode.Single);
}
}
#endregion
#region 方式二
/// <summary>
/// 加载ab包的场景(单个)
/// 注:加载场景的时候可能会出现一个问题,那就是场景里面存在一个ab包的预制体,但你再去加载这个预制体就会报错。(解决办法就是把你场景里面的那个预制体删掉就可以了)
/// </summary>
private void LoadBundleScene()
{
myLoadedAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + sceneName);
scenePaths = myLoadedAssetBundle.GetAllScenePaths();
SceneManager.LoadScene(scenePaths[0], LoadSceneMode.Single);
}
private AssetBundle myLoadedAssetBundle;
private string[] scenePaths;
#endregion
}
以上就是一整套的打包和加载了。
方法三:
因为第一种没测试过是否会把预制体的依赖资源一起打进去,所以才有了这第三种方法的记录。
Editor目录下的打包脚本: CreateAssetBundles.cs(对了,这个方法预制体打标签时不能有后缀,只能有名字)
using UnityEditor;
using System.IO;
public class CreateAssetBundles
{
[MenuItem("Assets/Build AssetBundles")]
static void BuildAssetBundles()
{
string dir = "AssetBundles";
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
}
}
这个路径是打包到Asset同一层级的目录下,加载测试脚本里面的路径是StreamingAssets目录下,所以需自行拖到StreamingAssets目录下。
加载脚本:DownLoadAssetBundles.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DownLoadAssetBundles : MonoBehaviour
{
void Start()
{
InstantiateBundlePrefab();
}
public string assetName;
AssetBundle asset;//实现可多次加载
/// <summary>
/// 加载ab包的预制体(单个)
/// </summary>
private void InstantiateBundlePrefab()
{
if (asset == null)
asset = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + assetName);
var asset_go = asset.LoadAsset<GameObject>(assetName);
Instantiate(asset_go);
}
}
以上就是方法三的打包和加载了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)