在使用Unity制作大型场景的时候,往往需要加载大量的数据文件,尤其是对于模型、材质、贴图、特效等资源都是项目中不可缺少的一部分。数据量越大,数组加载就越慢,让用户长时间等待是一种非常差的体验。
因此在项目制作前必须先要解决场景数据管路的问题。Unity3D提供了一种被叫做 AssetBundles(资源束)的外部整合数据,可以供我们资源管理使用。
在游戏的运作当中,更新资源必不可少。我们可以将他们制作成Prefab,包成AssetBundle,方便我们后面使用来达到资源更新的效果。
1.首先在场景中新建3个物体,分别是:Cube,Sphere, Capsule,分别把他们拉成预制体。
2.分别点击预制体,给每个预制体设置 AssetBundle 的名字
这里我们对AssetBundle 下拉框这里面的选项进行一下解释!~
None: 表示AssetBundle的名称为空
New…:设置AssetBundle的名称(名称默认小写表示)
Remove Unused Names: 移除没有使用到的 AssetBundle的名称
Filter Selected Name: 筛选出使用该AssetBundle名称的所有物体
3.上面的AssetBundle的名称设置好之后,我们开始编写——打包脚本(脚本放在Editor文件夹下)
using UnityEditor;
using UnityEngine;
public class BuildAssetBundle{
/// <summary>
/// 点击后,所有设置了AssetBundle名称的资源会被 分单个打包出来
/// </summary>
[MenuItem("AssetBundle/Build (Single)")]
static void Build_AssetBundle()
{
BuildPipeline.BuildAssetBundles(Application.dataPath + "/Test_AssetBundle", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
//刷新
AssetDatabase.Refresh();
}
/// <summary>
/// 选择的资源合在一起被打包出来
/// </summary>
[MenuItem("AssetBundle/Build (Collection)")]
static void Build_AssetBundle_Collection()
{
AssetBundleBuild[] buildMap = new AssetBundleBuild[1];
//打包出来的资源包名字
buildMap[0].assetBundleName = "enemybundle";
//在Project视图中,选择要打包的对象
Object[] selects = Selection.GetFiltered(typeof(Object), SelectionMode.DeepAssets);
string[] enemyAsset = new string[selects.Length];
for (int i = 0; i < selects.Length; i++)
{
//获得选择 对象的路径
enemyAsset[i] = AssetDatabase.GetAssetPath(selects[i]);
}
buildMap[0].assetNames = enemyAsset;
BuildPipeline.BuildAssetBundles(Application.dataPath + "/Test_AssetBundle", buildMap, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
//刷新
AssetDatabase.Refresh();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
上面打包AssetBundle的代码,主要一句
//“Application.dataPath + /Test_AssetBundle” --AssetBundle导出到的文件夹的位置
//“BuildAssetBundleOptions.None” --构建AssetBundle没有任何特殊的选项
//“BuildTarget.StandaloneWindows” --AssetBundle的构建平台(这个需要注意,这里测试的电脑端,Android、IOS等需要另外选择)
BuildPipeline.BuildAssetBundles(Application.dataPath + "/Test_AssetBundle", BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
- 1
- 2
- 3
- 4
打包出来的 AssetBundle
这里打包的 “enemybundle”, 我选择的是三个预设体(Cube、Sphere、Capsule)打包在了一起;
这里显示的打包出来的AssetBundle包含的物体的信息
4.打包脚本编写完成后,接下来编写——读取脚本
using System.Collections;
using UnityEngine;
public class LoadAssetBundle : MonoBehaviour{
public static string BundleURL;
private void Awake()
{
//平台预处理
BundleURL =
#if UNITY_ANDROID
"jar:file://" + Application.dataPath + "!/assets/";
#elif UNITY_IPHONE
Application.dataPath + "/Raw/";
#elif UNITY_STANDALONE_WIN || UNITY_EDITOR
"file://" + Application.dataPath + "/Test_AssetBundle/";//Test_AssetBundle 资源束文件的位置
#else
string.Empty;
#endif
}
void OnGUI()
{
if (GUI.Button(new Rect(20,20,300,100),"点击加载Asset"))
{
//BundleURL + "enemybundle" 要加载的文件地址
StartCoroutine(DownLoadAssetAndScene(BundleURL + "cub"));
//StartCoroutine(DownLoadAssetAndScene(BundleURL + "sph"));
//StartCoroutine(DownLoadAssetAndScene(BundleURL + "cap"));
//StartCoroutine(DownLoadAssetAndScene(BundleURL + "enemybundle"));
}
}
IEnumerator DownLoadAssetAndScene(string path)
{
//电脑端加载使用
WWW asset = new WWW(path);
yield return asset;
AssetBundle bundle = asset.assetBundle;
//资源加载
//加载的是打包到资源包里面,每个资源的名字
Instantiate(bundle.LoadAsset("Cube.prefab"));
//Instantiate(bundle.LoadAsset("Sphere.prefab"));
//Instantiate(bundle.LoadAsset("Capsule.prefab"));
//资源加载完毕后记得Unload,不然再次加载资源的时候无法加载
bundle.Unload(false);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
加载出来资源的位置就是AssetBundle时候,资源在场景中的位置。
值得一提的是,在加载完资源后立即通过AssetBundle.Unload(false)释放AssetBundle(资源束)文件本身的内存镜像,但不销毁加载的Asset(资源)对象。这样就不用保存AssetBundle(资源束)的引用,且可以立即释放一部分内存。释放时,如果有Instantiate(实例化)的对象,用Destroy(毁灭)进行销毁。
介绍几个释放代码:
- Destroy:主要用于销毁克隆对象,也可以用于场景内的静态物体,但不会自动释放该对象的所有引用。
- AssetBundle.Unload(false):释放AssetBundle(资源束)文件内存镜像。
- AssetBundle.Unload(true):释放AssetBundle(资源束)文件内存镜像,同时销毁所以已经Load(下载)的Assets(资源)内存对象。
- Resources.UnloadUnusedAssets:用于释放所以没有引用的Asset(资源)对象。
需要注意的是:**
平台为电脑端:加载AssetBundle的时候一切正常。
平台为安卓端:会出现错误。
认为是加载方法的问题,目前还没找到答案!!
希望各位朋友,留言交流!!