本文节选自洪流学堂公众号技术专栏《大话Unity2019》,未经允许不可转载。
洪流学堂公众号回复专栏
,查看更多专栏文章。
洪流学堂,让你快人几步。你好,我是郑洪智。
小新:“昨天这个动态配置和获取文本、图片很实用啊,那如果要动态替换模型的话要怎么做呢?”
大智:“动态替换模型会麻烦一些,但也不是不可以。从今天开始我们就来学习一下如何去动态加载模型,首先要了解的是Unity中的Assetbundle。”
Assetbundle
Assebundle可以理解为是Unity中的一种压缩包,这个压缩包可以包含针对特定平台的资源(模型、贴图、Prefab、音频甚至整个场景),并且可以在运行时动态加载。
Assebundle中可以有依赖关系,比如AssetBundle A中的材质球可以引用AssetBundle B中的贴图。
另外为了网络传输的效率更高,AssetBundle可以选择使用内置的压缩算法进(LZMA和LZ4)行压缩。
Assebundle能带来的明显的好处是:
- 有了Assetbundle就可以减小初始包的尺寸,可以后续通过网络进行下载和更新,实现资源的热更新。
- assetbundle资源是针对特定平台优化过的资源,可以减少运行时内存的压力。
Assetbundle中有什么?
一个Assetbundle实际上有两部分组成,这两部分是有关联的。
一部分是包含资源的文件,叫做Assetbundle压缩包。压缩包里有两种文件类型:序列化文件和资源文件。序列化文件比如场景、Prefab等,资源文件比如贴图、模型网格、音频、视频等二进制数据。
另一部分是压缩包中包含资源的映射信息。通过代码加载Assetbundle时就需要从这一部分中获取资源对应的位置信息。
Assetbundle的工作流程简介
下面我们先简单介绍一下使用Assetbundle的工作流程,后面会详细介绍。
1. 将资产标记为Assetbundle
想要标记一个资产为Assetbundle,一般有下面几步:
1、在Project窗口中选中想要标记为assetbundle的资产
2、在Inspector中检查一下这个资产
3、在Inspector的底部,你可以看到一个设置assetbundle和名称的区域
4、左边的下拉框用来设置所在的Assetbundle,右边的下拉框用来设置资产在assetbundle中的名称
5、点击左侧的下拉框,可以看到工程内所有的assetbundle名称
6、点击“New…”可以创建一个新的Assetbundle
7、输入你想要的Assetbundle名称。虽然这个叫名称,但是支持文件夹结构的路径。如果你想将Assetbundle放入一个子文件夹里,你可以在名称内输入/
来分割。比如:一个environment/forest
的名称会将名为forest的assetbundle创建到environment子文件夹下。
8、创建完assetbundle的名称路径后,可以在右边的下拉框中创建资产名称。不过这个名称是可选的,如果不设置,会默认是资产的名称。
2.构建Assetbundle文件
创建Assetbundle的文件需要通过一些简单的代码来完成。
1、在Project中创建一个Editor文件夹
2、创建一个脚本,命名为BuildAssetbundles.cs
,内容为:
using System.IO;
using UnityEditor;
using UnityEngine;
public class CreateAssetBundles
{
[MenuItem("Assets/Build AssetBundles")]
static void BuildAllAssetBundles()
{
string assetBundleDirectory = Application.streamingAssetsPath;
if (!Directory.Exists(assetBundleDirectory))
{
Directory.CreateDirectory(assetBundleDirectory);
}
BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
}
}
这个脚本会在菜单栏Asset中创建一个名为Build AssetBundles
的菜单,点击后后会执行上面代码中的方法。
方法开始执行后,会显示打包的进度条,和Build有点像。
3.加载Assetbundle
Assetbundle可以存放在多种位置,可以存在本地,也可以存放在网络服务器上下载后加载。
从文件加载
如果Assetbundle文件存放在本地,可以直接从本地加载,无需网络下载的过程。
using System.IO;
using UnityEngine;
public class LoadFromFileExample : MonoBehaviour
{
void Start()
{
var myLoadedAssetBundle = AssetBundle.LoadFromFile(Path.Combine(Application.streamingAssetsPath, "myassetBundle"));
if (myLoadedAssetBundle == null)
{
Debug.Log("Failed to load AssetBundle!");
return;
}
var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("MyObject");
Instantiate(prefab);
}
}
从网络下载
Assetbundle也可以放到服务器上,通过网络下载进行加载。这也是实现资源热更新的原理。
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
public class LoadFromNetwork : MonoBehaviour
{
IEnumerator Start()
{
var uri = new Uri(Application.streamingAssetsPath);
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri);
yield return request.SendWebRequest();
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
GameObject cube = bundle.LoadAsset<GameObject>("Cube");
Instantiate(cube);
}
}
总结
上面这些呢,就是使用Assetbundle的大致的流程,后面几天,我们还会详细的分析每一步以及可能会遇到的问题。
今日思考题
大智:“试着打包一个Cube的prefab,看看可不可以动态加载出来”
小新:“好嘞!”
大智:“收获别忘了分享出来!也别忘了分享给你学Unity的朋友,也许能够帮到他。”
洪流学堂公众号回复专栏
,查看更多专栏文章。
《大话Unity2019》,大智带小新学Unity2019的有趣经历,让你学Unity更简单。