Unity AssetBundle批量打包、加载(场景、Prefab)完整流程

2023-11-02 22:47

本文主要是介绍Unity AssetBundle批量打包、加载(场景、Prefab)完整流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1、文章介绍

2、具体思路和写法

        (1)AB包的打包

        (2)AB包的加载

        (3)AB包卸载

3、结语

1、文章介绍

本篇博客主要起记录和学习作用,简单的介绍一下AB包批量的打包和加载AB包的方式,若各位同学有幸看到本篇博客,希望能够对你有所帮助。

2、具体的思路和写法

(1)AB包的打包

先介绍一下打ab包所要用到的api  BuildPipeline.BuildAssetBundle(string outputPath,AssetBundleBuild[] builds,BuildAssetBundleOptions assetBundleOptions,BuildTarget targetPlatform)

参数1:ab包输出路径  参数2:ab包信息(主要是assetBundleName=ab包名字,assetNames=资源名)   注意:assetNames一定是要Assets下的路径,不要使用windows路径,不然打包会报错!!!

    /// <summary>///   <para>Build AssetBundles from a building map.</para>/// </summary>/// <param name="outputPath">Output path for the AssetBundles.</param>/// <param name="builds">AssetBundle building map.</param>/// <param name="assetBundleOptions">AssetBundle building options.</param>/// <param name="targetPlatform">Target build platform.</param>/// <returns>///   <para>The manifest listing all AssetBundles included in this build.</para>/// </returns>public static AssetBundleManifest BuildAssetBundles(string outputPath,AssetBundleBuild[] builds,BuildAssetBundleOptions assetBundleOptions,BuildTarget targetPlatform){BuildTargetGroup buildTargetGroup = BuildPipeline.GetBuildTargetGroup(targetPlatform);return BuildPipeline.BuildAssetBundles(outputPath, builds, assetBundleOptions, buildTargetGroup, targetPlatform);}

打包之前的准备工作:

        一般ToB的小项目会有一些资源迭代的需求,所以场景资源单独放到文件夹中管理,每次有新的迭代时,只对最新版本中的场景资源进行增量打包。

        UI资源同样的道理,但是小项目UI资源不需要分版本管理,除非是企业级的项目需要热更或者需要版本管理,则分版本管理。

 

下面是具体代码:

        打包的时候需要注意的事项,打场景包一定不能压缩,否则会加载不出来要使用BuildAssetBundleOptions.None。打其他资源的时候可以选择LZ4压缩BuildAssetBundleOptions.ChunkBasedCompression。LZ4压缩是LZMA和不压缩之间的折中方案,构建的 AssetBundle 资源文件会略大于 LZMA 压缩,但是在加载资源时不需要将所有的资源都加载下来,所以速度会比 LZMA 快。建议项目中使用它。

using System;
using System.Collections.Generic;
using System.IO;
using NWH.Common.AssetInfo;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;namespace editor.AssetBundle
{public class BuildAssetBundle : Editor{/// <summary>/// 场景资源路径/// </summary>private static string _scenePath = $"{Application.dataPath}/AssetBundle/";/// <summary>/// UI资源路径/// </summary>private static string _uiPath = $"{Application.dataPath}/AssetBundle/Resources/";/// <summary>/// 最终场景包输出目录/// </summary>public static string SceneOutPutPath = $"{Application.persistentDataPath}/assetbundle_orgin";/// <summary>/// 最终prefab包输出目录/// </summary>public static string UiOutputPath = $"{Application.persistentDataPath}/assetbundle_uiorgin";[MenuItem("UnityTools/打包资源")]public static void BuildAssetsBundle(){BuildAllScenes();BuildAllPrefabs();//刷新文件AssetDatabase.Refresh();}private static void BuildAllScenes(){var directorys = Directory.GetDirectories(_scenePath, "V*");var folder = directorys[directorys.Length - 1];//获取指定文件夹下所有的.unity文件var sceneFiles = Directory.GetFiles(folder + $"/Scenes/", $"*.unity",SearchOption.AllDirectories);for (int i = 0; i < sceneFiles.Length; i++){//打包进度EditorUtility.DisplayProgressBar($"正在打包场景中...", sceneFiles[i], 1.0f);if (!Directory.Exists(SceneOutPutPath)){Directory.CreateDirectory(SceneOutPutPath);}//批量打包所有的.unity文件  设置输出路径和输出windows平台AssetBundleBuild buildPacket = new AssetBundleBuild();buildPacket.assetBundleName = $"{Path.GetFileNameWithoutExtension(sceneFiles[i]).ToLower()}.unity3d";buildPacket.assetNames = new string[] { sceneFiles[i].Substring(sceneFiles[i].IndexOf("Assets/")) };var abManifest = BuildPipeline.BuildAssetBundles(SceneOutPutPath,new AssetBundleBuild[]{buildPacket},BuildAssetBundleOptions.None,BuildTarget.StandaloneWindows64);}EditorUtility.ClearProgressBar();}private static void BuildAllPrefabs(){//获取指定文件夹下所有的.prefab文件var uiFiles = Directory.GetFiles(_uiPath, $"*.prefab",SearchOption.AllDirectories);if (!Directory.Exists(UiOutputPath)){Directory.CreateDirectory(UiOutputPath);}List<AssetBundleBuild> buildInfoList = new List<AssetBundleBuild>();for (int i = 0; i < uiFiles.Length; i++){//打包进度EditorUtility.DisplayProgressBar($"正在打包预设中...", uiFiles[i], 1.0f);AssetBundleBuild buildInfo = new AssetBundleBuild();buildInfo.assetBundleName = $"{Path.GetFileNameWithoutExtension(uiFiles[i]).ToLower()}.unity3d";buildInfo.assetNames = new string[] { uiFiles[i].Substring(uiFiles[i].IndexOf("Assets/")) };buildInfoList.Add(buildInfo);AssetBundleManifest buildManifest = BuildPipeline.BuildAssetBundles(UiOutputPath, buildInfoList.ToArray(), BuildAssetBundleOptions.ChunkBasedCompression, BuildTarget.StandaloneWindows64);}EditorUtility.ClearProgressBar();}}
}

 打包完成后输出的文件:

(2)AB包的加载

        加载场景和UI资源我使用的是同步加载,需要用到异步加载或者网络加载的同学可以去看看其他的文章介绍。      

AssetBundle.LoadFromFile 从磁盘上的文件同步加载 AssetBundle。该函数支持任意压缩类型的捆绑包。 如果是 lzma 压缩,则将数据解压缩到内存。可以从磁盘直接读取未压缩和使用块压缩的捆绑包。

与 LoadFromFileAsync 相比,该版本是同步的,将等待 AssetBundle 对象创建完毕才返回。

这是加载 AssetBundle 的最快方法。

using System.Collections;
using System.Collections.Generic;
using UnityEditor.VersionControl;
using UnityEngine;
using utils;public class ABMgr : IMgr<ABMgr>
{/// <summary>/// 包路径/// </summary>private string packagePath;/// <summary>/// ab包缓存/// </summary>private Dictionary<string, AssetBundle> abCache;/// <summary>/// 主包/// </summary>private AssetBundle mainAB = null;/// <summary>/// 主包中的配置文件---->用来获取依赖包/// </summary>private AssetBundleManifest manifest = null;protected override void Init(){base.Init();abCache = new Dictionary<string, AssetBundle>();packagePath = $"{Application.persistentDataPath}/assetbundle_uiorgin/";}private AssetBundle LoadABPackage(string abName){AssetBundle ab;if (mainAB == null){mainAB = AssetBundle.LoadFromFile(packagePath + "assetbundle_uiorgin");manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");}var dependencies = manifest.GetAllDependencies(abName);for (int i = 0; i < dependencies.Length; i++){if (!abCache.ContainsKey(dependencies[i])){ab = AssetBundle.LoadFromFile(packagePath + dependencies[i]);abCache.Add(dependencies[i], ab);}}if (abCache.ContainsKey(abName)) return abCache[abName];else{ab = AssetBundle.LoadFromFile(packagePath + abName);abCache.Add(abName, ab);return ab;}}public T LoadResources<T>(string abName, string resName) where T : Object{AssetBundle ab = LoadABPackage(abName);return ab.LoadAsset<T>(resName);}
}

 ab包加载单例基类:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace utils
{public class IMgr<T> : MonoBehaviour where T: IMgr<T>{private static T instance;public static T Instance{get{if (instance != null) return instance;instance = FindObjectOfType<T>();//防止脚本还未挂到物体上,找不到的异常情况,自行创建空物体挂上去if (instance == null){new GameObject("IMgrTo" +typeof(T)).AddComponent<T>();}else instance.Init(); //保证Init只执行一次return instance;}}private void Awake(){instance = this as T;Init();}protected virtual void Init(){}}
}

 下面随便写一个例子看看加载出来的效果:

 

    // Update is called once per framevoid Update(){if (Input.GetKeyDown(KeyCode.Space)){OnLoadScene();}if (Input.GetKeyDown(KeyCode.A)){var go = GameObject.Find("Canvas")?.gameObject;//加载资源var testui = Instantiate(ABMgr.Instance.LoadResources<GameObject>("testui.unity3d", "testui"));if (testui != null && go != null){testui.transform.SetParent(go.transform);testui.transform.localPosition = Vector3.zero;testui.transform.localScale = Vector3.one;}}}private void OnLoadScene(){var ab = AssetBundle.LoadFromFile($"{Application.persistentDataPath}/assetbundle_orgin/scene1.unity3d");Debug.LogError(ab.name);SceneManager.LoadScene("scene1", LoadSceneMode.Additive);}
(3)AB包的卸载

        在AssetBundle的资源使用完成后,需要对其进行卸载,以释放其占用的内存空间。AssetBundle的卸载主要靠AssetBundle.Unload这个API实现。该方法需要传入一个bool类型的参数,如果传入的是true,则会卸载AssetBundle本身及从AssetBundle加载的全部资源。如果传入的是false,则会保留已经加载的资源。
在大多数情况下都推荐使用AssetBundle.Unload(true),因为如果传入false会
造成内存资源的浪费。

如果不得不使用AssetBundle.Unload(false),则只能用以下两种方式卸载单个对象:

在场景和代码中消除对不需要的对象的所有引用。完成此操作后,调用Resources.UnloadUnusedAssets。
以非附加方式加载场景。这样会销毁当前场景中的所有对象并自动调用Resources.UnloadUnusedAssets。

// 1.解除引用后调用
Resources.UnloadUnusedAssets();
// 2.上文提到的,卸载ab所加载的所有asset
ab.Unload(true);

3、结语

        这篇文章到这里就结束了,主要是记录一下自己在项目中使用到的对场景和UI打AB包用法,后续还会进行更深入的研究资源加密、解密、分类管理等等。希望这篇文章对你有帮助,喜欢的朋友点个赞吧。谢谢。

这篇关于Unity AssetBundle批量打包、加载(场景、Prefab)完整流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/333820

相关文章

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

springboot3打包成war包,用tomcat8启动

1、在pom中,将打包类型改为war <packaging>war</packaging> 2、pom中排除SpringBoot内置的Tomcat容器并添加Tomcat依赖,用于编译和测试,         *依赖时一定设置 scope 为 provided (相当于 tomcat 依赖只在本地运行和测试的时候有效,         打包的时候会排除这个依赖)<scope>provided

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

PostgreSQL核心功能特性与使用领域及场景分析

PostgreSQL有什么优点? 开源和免费 PostgreSQL是一个开源的数据库管理系统,可以免费使用和修改。这降低了企业的成本,并为开发者提供了一个活跃的社区和丰富的资源。 高度兼容 PostgreSQL支持多种操作系统(如Linux、Windows、macOS等)和编程语言(如C、C++、Java、Python、Ruby等),并提供了多种接口(如JDBC、ODBC、ADO.NET等

Python:豆瓣电影商业数据分析-爬取全数据【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】

**爬取豆瓣电影信息,分析近年电影行业的发展情况** 本文是完整的数据分析展现,代码有完整版,包含豆瓣电影爬取的具体方式【附带爬虫豆瓣,数据处理过程,数据分析,可视化,以及完整PPT报告】   最近MBA在学习《商业数据分析》,大实训作业给了数据要进行数据分析,所以先拿豆瓣电影练练手,网络上爬取豆瓣电影TOP250较多,但对于豆瓣电影全数据的爬取教程很少,所以我自己做一版。 目

火语言RPA流程组件介绍--浏览网页

🚩【组件功能】:浏览器打开指定网址或本地html文件 配置预览 配置说明 网址URL 支持T或# 默认FLOW输入项 输入需要打开的网址URL 超时时间 支持T或# 打开网页超时时间 执行后后等待时间(ms) 支持T或# 当前组件执行完成后继续等待的时间 UserAgent 支持T或# User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器