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包用法,后续还会进行更深入的研究资源加密、解密、分类管理等等。希望这篇文章对你有帮助,喜欢的朋友点个赞吧。谢谢。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/127619.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【HeidiSql_01】python在heidisql当中创建新表的注意事项

python在heidisql当中创建新表的注意事项 假设你已经在python当中弄好了所有的结果&#xff0c;并且保存在df_all这个dataframe当中&#xff0c;然后要将其导入数据库当中并创建一张新的表进行保存。 # 构建数据库连接,将merged_df写回数据库 from sqlalchemy import create_e…

Spring-创建非懒加载的单例Bean源码

补充&#xff1a;关于扫描的逻辑 /*** Scan the class path for candidate components.* param basePackage the package to check for annotated classes* return a corresponding Set of autodetected bean definitions*/ public Set<BeanDefinition> findCandidateCo…

【python】爬取豆瓣电影排行榜TOP250存储到CSV文件中

一、导入必要的模块&#xff1a; 代码首先导入了需要使用的模块&#xff1a;requests、lxml和csv。 import requests from lxml import etree import csv 如果出现模块报错 进入控制台输入&#xff1a;建议使用国内镜像源 pip install 模块名称 -i https://mirrors.aliyun.co…

【k8s】pod详解

一、Pod介绍 1、Pod的基础概念 Pod是kubernetes中最小的资源管理组件&#xff0c;Pod也是最小化运行容器化应用的资源对象&#xff0c;一个pod代表着集群中运行的一个进程。kubernetes中其它大多数组件都是围绕着pod来进行支持和扩展pod功能的。 例如&#xff0c;用于管理po…

构建强大的Web应用之Django详解

引言&#xff1a; Django是一个功能强大且灵活的Python Web框架&#xff0c;它提供了一套完整的工具和功能&#xff0c;帮助开发者快速构建高效的Web应用。本篇文章将带您逐步了解Django的基本概念和使用方法&#xff0c;并通过实际的代码案例&#xff0c;帮助您从零开始构建自…

Collction的List方法,list特有方法,遍历方式,迭代器选择

[to] list特有方法 //插入指定元素//list.add(1,"ddd");//System.out.println(list);//[aaa, ddd, bbb, ccc]//这个表示在一索引的位置插入ddd//他会把原来一索引位置的元素往后移动一位在添加//删除指定元素//String remove list.remove(1);//System.out.println(…

常用排序算法

目录 直接插入排序 希尔排序 ​编辑 选择排序 堆排序 冒泡排序 快速排序 hoare版 挖坑法 前后指针法 非递归 归并排序 非递归 计数排序 直接插入排序 直接插入排序跟依次模扑克牌一样&#xff0c;将最后一张牌依次与前面的牌比较&#xff0c;最后将牌插入到指定位…

创建ABAP数据库表和ABAP字典对象-使用已存在的数据元素增加城市字段04

基于内置域增加一个字段 1.在编辑器中&#xff0c;输入字段的名称&#xff0c;后跟冒号:city:。暂时忽略这个错误。2. 输入/MOC/C并使用自动补全(**Ctrl空格**)&#xff0c;输入类型。3. 然后添加一个分号:city: /moc/city;4.在SAP GUI中查看&#xff0c;字段已经新增

MATLAB野外观测站生态气象数据处理分析实践应用

1.基于MATLAB语言 2.以实践案例为主&#xff0c;提供所有代码 3.原理与操作结合 4.布置作业&#xff0c;答疑与拓展 示意图&#xff1a; 以野外观测站高频时序生态气象数据为例&#xff0c;基于MATLAB开展上机操作&#xff1a; 1.不同生态气象要素文件的数据读写与批处理实现 …

QT-- out of memory, returning null image

提示&#xff1a;本文为学习内容&#xff0c;若有错误&#xff0c;请及时联系作者&#xff0c;谦虚受教 文章目录 前言一、崩溃信息二、错误原因1.QImage2.QStandardItemModel 三、问题解决总结 前言 学如逆水行舟&#xff0c;不进则退。 一、崩溃信息 崩溃信息: QImage: out…

Go命令行参数操作:os.Args、flag包

Go命令行参数操作&#xff1a;os.Args、flag包 最近在写项目时&#xff0c;需要用到命令行传入的参数&#xff0c;正好借此机会整理一下。 1 os.Args&#xff1a;程序运行时&#xff0c;携带的参数&#xff08;包含exe本身&#xff09; package mainimport ("fmt"&q…

uniapp实现路线规划

UniApp是一个基于Vue.js框架开发的跨平台应用开发框架&#xff0c;可以同时构建iOS、Android、H5等多个平台的应用。它使用了基于前端技术栈的Web开发方式&#xff0c;通过编写一套代码&#xff0c;即可在不同平台上运行和发布应用。 UniApp具有以下特点&#xff1a; 跨平台开…

成集云 | 钉钉集成用友T费用报销付款接口 |解决方案

源系统成集云目标系统 方案介绍 钉钉是一款免费沟通和协同的多端平台&#xff0c;提供PC版、Web版和手机版&#xff0c;支持手机和电脑间文件互传。钉钉帮助中国企业通过系统化的解决方案&#xff08;微应用&#xff09;&#xff0c;提升中国企业的沟通和协同效率。应用场景包…

动手学深度学习 - 学习环境配置

学习环境配置 1、安装 Miniconda1.1 下载 miniconda31.2 环境变量配置1.3 安装成功测试1.4 配置文件1.5 使用conda创建、使用、删除环境1.6 conda 常用命令 2、使用 miniconda 安装 d2l2.1 下载 d2l 安装包2.2 安装 d2l 1、安装 Miniconda 参考&#xff1a; https://www.jb51.n…

Mac电脑风扇控制推荐 Macs Fan Control Pro 中文 for mac

Macs Fan Control Pro是一款功能全面、易于使用且具有良好兼容性和安全性的风扇控制软件&#xff0c;适用于各种Mac用户。 除了能够调整风扇速度外&#xff0c;Macs Fan Control Pro还支持实时监测硬件传感器的温度&#xff0c;例如CPU、硬盘等&#xff0c;同时显示每个传感器…

Java进阶(List)——面试时List常见问题解读 结合源码分析

前言 List、Set、HashMap作为Java中常用的集合&#xff0c;需要深入认识其原理和特性。 本篇博客介绍常见的关于Java中List集合的面试问题&#xff0c;结合源码分析题目背后的知识点。 关于的Set的博客文章如下&#xff1a; Java进阶&#xff08;Set&#xff09;——面试时…

【flink】Task 故障恢复详解以及各重启策略适用场景说明

文章目录 一. 重启策略种类&#xff08;Restart Strategies&#xff09;1. Fixed Delay Restart Strategy2. Failure Rate Restart Strategy3. Fallback Restart Strategy4. No Restart Strategy 二. 故障恢复策略&#xff08;Failover Strategies&#xff09;1. &#xff08;全…

spring解决后端显示时区的问题

spring解决后端显示时区的问题 出现的问题&#xff1a; 数据库中的数据&#xff1a; 解决方法 spring:jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: Asia/Shanghai

【JAVA学习笔记】55 - 集合-Map接口、HashMap类、HashTable类、Properties类、TreeMap类(难点)

项目代码 https://github.com/yinhai1114/Java_Learning_Code/tree/main/IDEA_Chapter14/src/com/yinhai/map_ Map接口 一、Map接口的特点&#xff08;难点&#xff09; 难点在于对Node和Entry和EntrySet的关系 注意:这里讲的是JDK8的Map接口特点 Map java 1) Map与Collect…

学习python必会知识点:if条件判断语句的运用

大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 if的基本格式 if语句用来做判断&#xff0c;并选择要执行的语句分支。 基本格式如下&#xff1a; if CONDITION1:code_block(1) elif CONDITION2:code_block(2) elif CO…