Unity AssetBundles(AB包)
目录
前言
AB包是什么
AB包有什么作用
1.相对Resources下的资源AB包更好管理资源
2.减小包体大小
3.热更新
官方提供的打包工具:Asset Bundle Browser
AB包资源加载
AB包资源管理模块代码
前言

在现代游戏开发中,资源管理是一项至关重要的任务。随着游戏内容的日益丰富和复杂,如何高效地加载、管理和卸载游戏资源成为了开发者们必须面对的挑战。Unity,作为一款广泛使用的游戏引擎,提供了一套强大的资源管理方案——AssetBundles(简称AB包)。
AB包是什么
特定于平台的资产压缩包,有点类似压缩文件
资产包括:模型、贴图、预设体、音效、材质球等等
AB包有什么作用
1.相对Resources下的资源AB包更好管理资源

2.减小包体大小
1.压缩资源
2.减少初始包大小
3.热更新
资源热更新
脚本热更新

官方提供的打包工具:Asset Bundle Browser
将以下脚本放置在Editor文件夹中
using UnityEditor;
using UnityEngine;public class CreateAssetBundles
{[MenuItem("Assets/Build AssetBundles")]static void BuildAllAssetBundles(){string assetBundleDirectory = "Assets/AssetBundles";if (!System.IO.Directory.Exists(assetBundleDirectory)){System.IO.Directory.CreateDirectory(assetBundleDirectory);}BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);}
}
创建AB包,选中资源,在Asset Bundle里选择New
我这里取名为icon

点击Asset/Build AssetBundles

这样就会在AssetBundles文件夹里生成一些资源文件

AB包文件:资源文件
manifest文件:AB包文件信息;当加载时,提供了关键信息,资源信息,依赖关系,版本信息等等
关键AB包(和目录名一样的包):主包,AB包依赖关键信息
AB包资源加载
将脚本挂载到Image上,启动项目,资源会从ab包中加载到sprite上
using UnityEngine;
using UnityEngine.UI;public class ABTest : MonoBehaviour
{// Start is called once before the first execution of Update after the MonoBehaviour is createdvoid Start(){//第一步 加载 AB包AssetBundle ab= AssetBundle.LoadFromFile("Assets/AssetBundles/icon");//第二步 加载 AB包中的资源//只是用名字加载 会出现 同名不同类型资源 分不清//建议用泛型或Type指定类型Sprite icon = ab.LoadAsset("item_0", typeof(Sprite)) as Sprite;GetComponent<Image>().sprite = icon;}// Update is called once per framevoid Update(){}
}

协程加载
using System.Collections;
using UnityEngine;
using UnityEngine.UI;public class ABTest : MonoBehaviour
{// Start is called once before the first execution of Update after the MonoBehaviour is createdvoid Start(){StartCoroutine(LoadABRes("item_0"));}IEnumerator LoadABRes(string resName){AssetBundleCreateRequest abcr = AssetBundle.LoadFromFileAsync("Assets/AssetBundles/icon");yield return abcr;//加载资源AssetBundleRequest abq= abcr.assetBundle.LoadAssetAsync(resName,typeof(Sprite));yield return null;GetComponent<Image>().sprite = abq.asset as Sprite;}}
卸载AB包
//卸载所有加载的AB包 参数为ture 会把通过AB包加载的资源也卸载了AssetBundle.UnloadAllAssetBundles(false);
关于AB包的依赖,一个资源身上用到了别的AB包中的资源,这个时候,如果只加载自己的AB包,通过它创建对象会出现资源丢失的情况,这种时候 需要把依赖包 一起加载了 才能正常。
依赖包的固定写法
using System.Collections;
using UnityEngine;
using UnityEngine.UI;public class ABTest : MonoBehaviour
{// Start is called once before the first execution of Update after the MonoBehaviour is createdvoid Start(){//第一步 加载 AB包AssetBundle ab = AssetBundle.LoadFromFile("AB包文件路径");//依赖包的关键知识点一利用主包 获取依赖信息//加载主包AssetBundle abMain = AssetBundle.LoadFromFile("主包文件路径");//加载主包中的固定文件AssetBundleManifest abManifest = abMain.LoadAsset<AssetBundleManifest> ("AssetBundleManifest");//从固定文件中 得到依赖信息string[] strs = abManifest.GetAllDependencies("AB包名");for (int i = 0; i < strs.Length; i++) {AssetBundle.LoadFromFile("前置路径/" + strs[i]);}}}
AB包资源管理模块代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;public class ABMgr : MonoBehaviour
{private static ABMgr instance;public static ABMgr GetInstance(){if (instance == null){GameObject obj = new GameObject();//设置对象的名字为脚本obj.name = typeof(GameObject).ToString();instance = obj.AddComponent<ABMgr>();}return instance;}//主包private AssetBundle mainAB = null;//主包依赖获取配置文件private AssetBundleManifest manifest = null;//选择存储 AB包的容器//AB包不能够重复加载 否则会报错//字典知识 用来存储 AB包对象private Dictionary<string, AssetBundle> abDic = new Dictionary<string, AssetBundle>();/// <summary>/// 获取AB包加载路径/// </summary>private string PathUrl{get{return Application.streamingAssetsPath + "/";}}/// <summary>/// 主包名 根据平台不同 报名不同/// </summary>private string MainName{get{
#if UNITY_IOSreturn "IOS";
#elif UNITY_ANDROIDreturn "Android";
#elsereturn "PC";
#endif}}/// <summary>/// 加载主包 和 配置文件/// 因为加载所有包是 都得判断 通过它才能得到依赖信息/// 所以写一个方法/// </summary>private void LoadMainAB(){if (mainAB == null){mainAB = AssetBundle.LoadFromFile(PathUrl + MainName);manifest = mainAB.LoadAsset<AssetBundleManifest>("AssetBundleManifest");}}/// <summary>/// 加载指定包的依赖包/// </summary>/// <param name="abName"></param>private void LoadDependencies(string abName){//加载主包LoadMainAB();//获取依赖包string[] strs = manifest.GetAllDependencies(abName);for (int i = 0; i < strs.Length; i++){if (!abDic.ContainsKey(strs[i])){AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + strs[i]);abDic.Add(strs[i], ab);}}}/// <summary>/// 泛型资源同步加载/// </summary>/// <typeparam name="T"></typeparam>/// <param name="abName"></param>/// <param name="resName"></param>/// <returns></returns>public T LoadRes<T>(string abName, string resName) where T : Object{//加载依赖包LoadDependencies(abName);//加载目标包if (!abDic.ContainsKey(abName)){AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);abDic.Add(abName, ab);}//得到加载出来的资源T obj = abDic[abName].LoadAsset<T>(resName);//如果是GameObject 因为GameObject 100%都是需要实例化的//所以我们直接实例化if (obj is GameObject)return Instantiate(obj);elsereturn obj;}/// <summary>/// Type同步加载指定资源/// </summary>/// <param name="abName"></param>/// <param name="resName"></param>/// <param name="type"></param>/// <returns></returns>public Object LoadRes(string abName, string resName, System.Type type){//加载依赖包LoadDependencies(abName);//加载目标包if (!abDic.ContainsKey(abName)){AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);abDic.Add(abName, ab);}//得到加载出来的资源Object obj = abDic[abName].LoadAsset(resName, type);//如果是GameObject 因为GameObject 100%都是需要实例化的//所以我们直接实例化if (obj is GameObject)return Instantiate(obj);elsereturn obj;}/// <summary>/// 名字 同步加载指定资源/// </summary>/// <param name="abName"></param>/// <param name="resName"></param>/// <returns></returns>public Object LoadRes(string abName, string resName){//加载依赖包LoadDependencies(abName);//加载目标包if (!abDic.ContainsKey(abName)){AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);abDic.Add(abName, ab);}//得到加载出来的资源Object obj = abDic[abName].LoadAsset(resName);//如果是GameObject 因为GameObject 100%都是需要实例化的//所以我们直接实例化if (obj is GameObject)return Instantiate(obj);elsereturn obj;}/// <summary>/// 泛型异步加载资源/// </summary>/// <typeparam name="T"></typeparam>/// <param name="abName"></param>/// <param name="resName"></param>/// <param name="callBack"></param>public void LoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T : Object{StartCoroutine(ReallyLoadResAsync<T>(abName, resName, callBack));}//正儿八经的 协程函数private IEnumerator ReallyLoadResAsync<T>(string abName, string resName, UnityAction<T> callBack) where T : Object{//加载依赖包LoadDependencies(abName);//加载目标包if (!abDic.ContainsKey(abName)){AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);abDic.Add(abName, ab);}//异步加载包中资源AssetBundleRequest abq = abDic[abName].LoadAssetAsync<T>(resName);yield return abq;if (abq.asset is GameObject)callBack(Instantiate(abq.asset) as T);elsecallBack(abq.asset as T);}/// <summary>/// Type异步加载资源/// </summary>/// <param name="abName"></param>/// <param name="resName"></param>/// <param name="type"></param>/// <param name="callBack"></param>public void LoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack){StartCoroutine(ReallyLoadResAsync(abName, resName, type, callBack));}private IEnumerator ReallyLoadResAsync(string abName, string resName, System.Type type, UnityAction<Object> callBack){//加载依赖包LoadDependencies(abName);//加载目标包if (!abDic.ContainsKey(abName)){AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);abDic.Add(abName, ab);}//异步加载包中资源AssetBundleRequest abq = abDic[abName].LoadAssetAsync(resName, type);yield return abq;if (abq.asset is GameObject)callBack(Instantiate(abq.asset));elsecallBack(abq.asset);}/// <summary>/// 名字 异步加载 指定资源/// </summary>/// <param name="abName"></param>/// <param name="resName"></param>/// <param name="callBack"></param>public void LoadResAsync(string abName, string resName, UnityAction<Object> callBack){StartCoroutine(ReallyLoadResAsync(abName, resName, callBack));}private IEnumerator ReallyLoadResAsync(string abName, string resName, UnityAction<Object> callBack){//加载依赖包LoadDependencies(abName);//加载目标包if (!abDic.ContainsKey(abName)){AssetBundle ab = AssetBundle.LoadFromFile(PathUrl + abName);abDic.Add(abName, ab);}//异步加载包中资源AssetBundleRequest abq = abDic[abName].LoadAssetAsync(resName);yield return abq;if (abq.asset is GameObject)callBack(Instantiate(abq.asset));elsecallBack(abq.asset);}//卸载AB包的方法public void UnLoadAB(string name){if (abDic.ContainsKey(name)){abDic[name].Unload(false);abDic.Remove(name);}}//清空AB包的方法public void ClearAB(){AssetBundle.UnloadAllAssetBundles(false);abDic.Clear();//卸载主包mainAB = null;}
}
相关文章:
Unity AssetBundles(AB包)
目录 前言 AB包是什么 AB包有什么作用 1.相对Resources下的资源AB包更好管理资源 2.减小包体大小 3.热更新 官方提供的打包工具:Asset Bundle Browser AB包资源加载 AB包资源管理模块代码 前言 在现代游戏开发中,资源管理是一项至关重要的任务。随着游戏内容…...
腾讯面试:如何解决哈希冲突?
我们面试时经常被问到HashMap是怎么解决哈希冲突的,很多同学对其含糊其词、一知半解。因此小编对相关知识进行了总结,希望帮助读者加深对其理解。 哈希表就是通过散列函数将键映射到定值,简单来说就是一个键对应一个值。 而通过散列函数映射…...
【动手学运动规划】 4.5 A*算法
我宁愿永远做我自己,也不愿成为别人,即使那个人比你更快乐。 —《成为简奥斯汀》 🏰代码及环境配置:请参考 环境配置和代码运行! 4.5.1 概述 Dijkstra算法是基于广度优先搜索策略来遍历空间内的所有节点,最终计算出…...
Spring Boot 3.4.0 发布:功能概览与示例
Spring Boot 3.4.0 带来了许多增强功能,使现代应用开发更加高效、便捷和强大。以下是最新功能的完整概述,以及一些帮助您快速入门的代码示例。 1. 应用程序版本管理 Spring Boot 引入了 spring.application.version 属性,方便开发者设置和访…...
【48】Android通过libjpeg-turbo库实现图片压缩
(1)公司为节约图片占用服务器存储资源成本,需要对Android手机客户端所传递到云存储服务器中的图片进行压缩,在不影响图片失真程度的情况下,最大限度的压缩图片以节省图片所占用的存储空间。 (2)…...
Linux输入设备应用编程
本章学习输入设备的应用编程,首先要知道什么是输入设备?输入设备其实就是能够产生输入事件的设备就称为输入设备,常见的输入设备包括鼠标、键盘、触摸屏、按钮等等,它们都能够产生输入事件,产生输入数据给计算机系统。…...
【Vulkan入门】03-创建Device
目录 先叨叨git信息关键代码VulkanEnv::CreateDevice() 编译并运行程序题外话 先叨叨 在上篇已经选择了一个合适的PhysicalDevice。 本篇要为这个PhysicalDevice创将一个Device。Device可以理解为APP与PhysicalDevice之间的代理。 所有APP与PhysicalDevice之间交互的资源都通过…...
【jvm】C2编译器
目录 1. 说明2. 编译流程3. 使用与配置4. 性能优化与监控5. 局限性 1. 说明 1.JVM(Java虚拟机)C2编译器是Java编译过程中的重要环节,专门用于将Java字节码编译成高效的本地机器代码,以提升Java程序的执行效率。2.特点:…...
使用 Acme.sh 自动生成和续签免费 SSL 证书(含通配符支持)
Acme.sh 是一个开源的脚本,能够从 ZeroSSL、Let’s Encrypt 等证书颁发机构(CA)获取免费的 HTTPS 证书。该脚本特别简单易用,并且支持多种验证方式。下面将详细介绍使用 Acme.sh 生成、安装和更新证书的各个步骤。 Github地址 使用…...
Android 图形系统之四:Choreographer
Choreographer 是 Android 系统中负责帧同步的核心组件,它协调输入事件、动画和绘制任务,以确保界面以固定频率(通常是每 16ms,一帧)流畅渲染。通过管理 VSYNC 信号和调度任务,Choreographer 是实现流畅 UI…...
CAP定理和BASE理论
CAP定理 CAP定理,也称为布鲁尔定理(Brewer’s Theorem),是分布式系统设计中的一个基本原理。它指出在分布式系统中,一致性(Consistency)、可用性(Availability)和分区容…...
笔记软件:我来、思源笔记、Obsidian、OneNote
最近wolai的会员到期了,促使我更新了一下笔记软件。 首先,wolai作为一个笔记软件,我觉得有很多做得不错的方面(否则我也不会为它付费2年了),各种功能集成得很全(公式识别这个功能我写论文的时候…...
试探互联网如何工作?
Reading: How_does_the_Internet_workhow-does-internet-work Watching:How the Internet Works in 5 Minutes Outline: 互联网通过全球互联的计算机和服务器网络工作,通过标准化协议进行通信。数据被分解成数据包,并使用互联…...
【c++笔试强训】(第三十篇)
目录 爱丽丝的⼈偶(贪⼼构造) 题目解析 讲解算法原理 编写代码 集合(排序) 题目解析 讲解算法原理 编写代码 爱丽丝的⼈偶(贪⼼构造) 题目解析 1.题目链接:登录—专业IT笔试面试备考平…...
微信小程序购物车全选反选功能以及合计
微信小程序基于Vant Weapp的购物车功能实现 1、单选 使用微信小程序原生表单组件checkbox和checkbox-group 注意:checkbox原生不支持bind:change事件,checkbox-group支持 <checkbox-group bindchange"handleCheck"><checkbox val…...
vue-qr在线生成二维码组件(vue2版本)
在对于二维码生成中有许多组件,下面介绍关于自定义比较高的vue-qr组件,能自定义设置背景颜色、背景图片、背景Gif图、实点和空白区的颜色、中心Logo的图片和边距。 依赖下载 注意: 直接npm下载最新版 有些项目可能运行会抱错 这时候你可以降…...
大语言模型技术相关知识-笔记整理
系列文章目录 这个系列攒了很久。主要是前段之间面试大语言模型方面的实习(被拷打太多次了),然后每天根据面试官的问题进行扩展和补充的这个笔记。内容来源主要来自视频、个人理解以及官方文档中的记录。方便后面的回顾。 文章目录 系列文章…...
SCP命令实现Linux中的文件传输
CP命令的主要作用是实现Linux与Linux系统之间的文件传输。 SCP命令时基于SSH协议,所以两台服务器的sshd服务必须处于开启状态,否则无法完成上传与下载操作。 #1.上传文件 scp linux本地文件路径 远程用户名@linux主机地址:远程路径 #2.下载文件 scp 远程用户名@linux主机地址…...
linux环境中后台运行java程序
在生产环境,我们通常需要让java进程后台运行,并且即使会话关闭,进程也依然存在。 使用的命令: nohup java -jar xxx.jar -> aaa.log 2>&1 & 详细介绍下上面这条命令 (1)nohup:…...
Go学习:变量
目录 1. 变量的命名 2. 变量的声明 3. 变量声明时注意事项 4. 变量的初始化 5. 简单例子 变量主要用来存储数据信息,变量的值可以通过变量名进行访问。 1. 变量的命名 在Go语言中,变量名的命名规则 与其他编程语言一样,都是由字母、数…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件
今天呢,博主的学习进度也是步入了Java Mybatis 框架,目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学,希望能对大家有所帮助,也特别欢迎大家指点不足之处,小生很乐意接受正确的建议&…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
