二、構建AssetBundle包
三、上傳AssetBundle到服務器
四、把AssetBundle放到本地
五、操作AssetBundle
六、完整例子
七、AssetBundle Manager管理工具
八、備注知識
一、設置assetBundleName
如果沒有設置AssetBundleName,會打包所有的Assets下的資源,如果設置,就只打包設置了名字的資源
1、在unity編輯器界面手動設置
輸入所需的AssetBundle名稱。請注意,AssetBundle名稱確實支持一種類型的文件夾結構,這取決於您鍵入的內容。要添加子文件夾,將文件夾名稱以“/”分隔。例如:AssetBundle名稱“environment/ forest”將在environment子文件夾下創建一個名為forest的包
2、遍歷所有要打包的資源,通過代碼修改assetBundleName
第一步:先獲取你要打包的資源的完整目錄
方法1:
先用Selection.objects返回場景中所有的對象,
然后用AssetDatabase.GetAssetPath(selected)獲取對象完整目錄
方法2:
用AssetPostprocessor的OnPostprocessAllAssets方法
方法3:
用IO流的DirectoryInfo.GetFileSystemInfos()
和FileInfonfo獲取完整目錄(這種方法要注意:獲取到的目錄如果是”\”或者”//”要替換為“/”)
第二步:用AssetImporter asset= AssetImporter.GetAtPath(path);方法獲取AssetImporter
第三步:用asset.assetBundleName=“text”設置AssetBundleName
有以下三種獲取目錄然后設置assetBundleName的方法
-
//Selection.objects返回場景中所有的對象
-
Object[] selects = Selection.objects;
-
foreach (Object selected in selects)
-
{
-
//返回所有對象相對於工程目錄的存儲路徑如Assets/_Scenes/Main.unity
-
string path = AssetDatabase.GetAssetPath(selected);
-
//把一個目錄的對象檢索為AssetImporter
-
AssetImporter asset = AssetImporter.GetAtPath(path);
-
asset.assetBundleName = selected.name; //設置Bundle文件的名稱
-
asset.assetBundleVariant = "unity3d";//設置Bundle文件的擴展名
-
asset.SaveAndReimport();
-
}
-
AssetDatabase.Refresh();
-
using UnityEngine;
-
using System.Collections;
-
using UnityEditor;
-
//文件描述:自動設置Assetbundle名字為文件夾名_文件名.unity3d;
-
public class AutoSetTextureUISprite : AssetPostprocessor
-
{
-
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
-
{
-
foreach (var str in importedAssets)
-
{
-
if (!str.EndsWith(".cs"))
-
{
-
AssetImporter importer = AssetImporter.GetAtPath(str);
-
importer.assetBundleName = str;
-
-
}
-
}
-
foreach (var str in deletedAssets)
-
{
-
if (!str.EndsWith(".cs"))
-
{
-
AssetImporter importer = AssetImporter.GetAtPath(str);
-
importer.assetBundleName = str;
-
}
-
}
-
for (var i = 0; i < movedAssets.Length; i++)
-
{
-
//Debug.Log("Moved Asset: " + movedAssets[i] + " from: " + movedFromAssetPaths[i]);
-
}
-
}
-
}
-
using UnityEngine;
-
using System.Collections;
-
using UnityEditor;
-
using System.IO;
-
-
/// <summary>
-
/// 把Resource下的資源打包成.unity3d 到StreamingAssets目錄下
-
/// </summary>
-
public class Builder : Editor
-
{
-
public static string sourcePath = Application.dataPath + "/Resources";
-
const string AssetBundlesOutputPath = "Assets/StreamingAssets";
-
-
//[MenuItem("Tools/AssetBundle/Build")]
-
public static void BuildAssetBundle()
-
{
-
ClearAssetBundlesName();
-
-
Pack(sourcePath);
-
-
string outputPath = Path.Combine(AssetBundlesOutputPath, Platform.GetPlatformFolder(EditorUserBuildSettings.activeBuildTarget));
-
if (!Directory.Exists(outputPath))
-
{
-
Directory.CreateDirectory(outputPath);
-
}
-
-
//根據BuildSetting里面所激活的平台進行打包
-
BuildPipeline.BuildAssetBundles(outputPath, 0, EditorUserBuildSettings.activeBuildTarget);
-
-
AssetDatabase.Refresh();
-
-
Debug.Log( "打包完成");
-
-
}
-
-
/// <summary>
-
/// 清除之前設置過的AssetBundleName,避免產生不必要的資源也打包
-
/// 之前說過,只要設置了AssetBundleName的,都會進行打包,不論在什么目錄下
-
/// </summary>
-
static void ClearAssetBundlesName()
-
{
-
int length = AssetDatabase.GetAllAssetBundleNames().Length;
-
Debug.Log(length);
-
string[] oldAssetBundleNames = new string[length];
-
for (int i = 0; i < length; i++)
-
{
-
oldAssetBundleNames[i] = AssetDatabase.GetAllAssetBundleNames()[i];
-
}
-
-
for (int j = 0; j < oldAssetBundleNames.Length; j++)
-
{
-
AssetDatabase.RemoveAssetBundleName(oldAssetBundleNames[j], true);
-
}
-
length = AssetDatabase.GetAllAssetBundleNames().Length;
-
Debug.Log(length);
-
}
-
-
static void Pack(string source)
-
{
-
DirectoryInfo folder = new DirectoryInfo(source);
-
FileSystemInfo[] files = folder.GetFileSystemInfos();
-
int length = files.Length;
-
for (int i = 0; i < length; i++)
-
{
-
if (files[i] is DirectoryInfo)
-
{
-
Pack(files[i].FullName);
-
}
-
else
-
{
-
if (!files[i].Name.EndsWith(".meta"))
-
{
-
file(files[i].FullName);
-
}
-
}
-
}
-
}
-
-
static void file(string source)
-
{
-
string _source = Replace(source);
-
string _assetPath = "Assets" + _source.Substring(Application.dataPath.Length);
-
string _assetPath2 = _source.Substring(Application.dataPath.Length + 1);
-
//Debug.Log (_assetPath);
-
-
//在代碼中給資源設置AssetBundleName
-
AssetImporter assetImporter = AssetImporter.GetAtPath(_assetPath);
-
string assetName = _assetPath2.Substring(_assetPath2.IndexOf("/") + 1);
-
assetName = assetName.Replace(Path.GetExtension(assetName), ".unity3d");
-
//Debug.Log (assetName);
-
assetImporter.assetBundleName = assetName;
-
}
-
-
static string Replace(string s)
-
{
-
return s.Replace("\\", "/");
-
}
-
}
-
-
public class Platform
-
{
-
public static string GetPlatformFolder(BuildTarget target)
-
{
-
switch (target)
-
{
-
case BuildTarget.Android:
-
return "Android";
-
case BuildTarget.iOS:
-
return "IOS";
-
case BuildTarget.WebPlayer:
-
return "WebPlayer";
-
case BuildTarget.StandaloneWindows:
-
case BuildTarget.StandaloneWindows64:
-
return "Windows";
-
case BuildTarget.StandaloneOSXIntel:
-
case BuildTarget.StandaloneOSXIntel64:
-
case BuildTarget.StandaloneOSXUniversal:
-
return "OSX";
-
default:
-
return null;
-
}
-
}
-
-
}
二、構建AssetBundle
1、在Assets中創建一個名為Editor的文件夾,並將一個腳本放在文件夾中
2、類要繼承Editor,引用命名空間using UnityEditor;
3、創建菜單目錄:[MenuItem("Assets/Build AssetBundles")]
4、調用打包方法
①用AssetBundleBuild類的方法
BuildAssetBundles(string outputPath, BuildAssetBundleOptionsassetBundleOptions, BuildTargettargetPlatform);
或者
BuildAssetBundles(string outputPath,AssetBundleBuild[] builds,BuildAssetBundleOptions assetBundleOptions, BuildTarget targetPlatform);
②參數說明:
outputPath:打包Bundle后存儲的目錄,如:Assets/AssetBundles,這個文件夾不會自動創建,如果它不存在的話,函數將會失敗,Directory.Exists(string path)判斷目錄是否存在,Directory.CreateDirectory(stringpath)創建目錄
BuildAssetBundleOptions:Bundle打包方式,none沒有任何特殊選項,UncompressedAssetBundle在構建Bundle時不要壓縮數據等等
BuildTarget:構建平台,如iphone,windows,android等
AssetBundleBuild[]:看備注知識5
③返回值:AssetBundleManifest,看備注知識6
5、備注知識:AssetBundleBuild
這個類與BuildAssetBundles一起使用。指定一個Bundle包的名稱assetBundleName和它將包含的資源(如多張圖片、音頻等)的名稱。
被傳遞給函數的AssetBundleBuild[]元素數組被稱為“構建映射”,並作為指定編輯器包內容的替代方法。
變量:
addressableNames:返回所有的addressableName數組
assetBundleName:AssetBundle的名字
assetBundleVariant:AssetBundle的擴展名如.unity
AssetBundle:指定屬於一個addressableName名字的所有資源名字,是一個數組,也就是一個addressableName名字下包含的所有資源名字
例子:在后面
6、備注知識AssetBundleManifest
包含所有創建Bundle包信息
⑴公開方法
GetAllAssetBundles返回所有的assetbundlenames,是一個string[]數組
GetAllAssetBundlesWithVariant返回所有使用給定擴展名的assetbundlenames,是一個string[]數組
GetAllDependencies(string assetBundleName);:獲取所有與指定AssetBundle包存在依賴關系的AssetBundless。也就是給一個assetBundleName,獲取所有與他有關系的assetBundleName,返回一個string[]數組
GetDirectDependencies(string assetBundleName):獲取所有與指定AssetBundle包存在直接聯系的AssetBundless。也就是給一個assetBundleName,獲取所有與他有直接關系的assetBundleName,返回一個string[]數組
⑵當找到這個對象后就可以對它進行操作7、例子
第一個方法
-
// 創建一個Windows AssetBundle包
-
using UnityEngine;
-
using UnityEditor;
-
using System.IO;
-
public class BuildAssetBundlesExample : MonoBehaviour
-
{
-
//創建編輯器菜單目錄
-
[
-
static void BuildABs()
-
{
-
//將這些資源包放在一個名為ABs的目錄下
-
string assetBundleDirectory = "Assets/ABs";
-
//如果目錄不存在,就創建一個目錄
-
if (!Directory.Exists(assetBundleDirectory))
-
{
-
Directory.CreateDirectory(assetBundleDirectory);
-
}
-
BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
-
}
-
}
-
using UnityEngine;
-
using UnityEditor;
-
using System.IO;
-
public class BuildAssetBundlesBuildMapExample : MonoBehaviour
-
{
-
[
-
static void BuildMapABs()
-
{
-
// 創建映射數組
-
AssetBundleBuild[] buildMap = new AssetBundleBuild[2];
-
-
//修改assetBundleName第一個
-
buildMap[ 0].assetBundleName = "enemybundle";
-
//assetBundleName = "enemybundle"下的所有資源名稱數組
-
string[] enemyAssets = new string[2];
-
enemyAssets[ 0] = "Assets/Textures/char_enemy_alienShip.jpg";
-
enemyAssets[ 1] = "Assets/Textures/char_enemy_alienShip-damaged.jpg";
-
buildMap[ 0].assetNames = enemyAssets;
-
-
//修改assetBundleName第二個
-
buildMap[ 1].assetBundleName = "herobundle";
-
//assetBundleName = "herobundle"下的所有資源名稱數組
-
string[] heroAssets = new string[1];
-
heroAssets[ 0] = "char_hero_beanMan";
-
buildMap[ 1].assetNames = heroAssets;
-
-
//創建Bundle包
-
-
//將這些資源包放在一個名為ABs的目錄下
-
string assetBundleDirectory = "Assets/ABs";
-
//如果目錄不存在,就創建一個目錄
-
if (!Directory.Exists(assetBundleDirectory))
-
{
-
Directory.CreateDirectory(assetBundleDirectory);
-
}
-
BuildPipeline.BuildAssetBundles(assetBundleDirectory, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
-
}
-
}
三、上傳AssetBundle到服務器
四、把AssetBundle放到本地
五、操作AssetBundle
1、從磁盤目錄加載AssetBundle包
⑴AssetBundle放在本地
public static AssetBundle LoadFromFile(string path uint crc = 0, ulong offset= 0);
說明:從path目錄同步加載AssetBundle,返回類型
AssetBundle(LoadFromFileAsync是異步加載)
參數:path讀取AssetBundle的目錄
crc 校驗用參數
offset這個值指定從哪里開始讀取AssetBundle,
通常為0
⑵ AssetBundle放在網絡
引用using UnityEngine.Networking;命名空間
UnityWebRequest.GetAssetBundle()方法看后面的詳細介紹
2、加載AssetBundle包之后,加載包內資源
注意:加載要用協程,否則你不知道是否加載完畢⑴加載一個資源
AssetBundle類
public Object LoadAsset(string name);
從AssetBundle包中加載名字為name的資源,返回object
public Object LoadAsset(string name, Type type);
加載一個包內名字為name,類型為type的資源
public T LoadAsset(string name);
搞不懂,也是加載名字為name類型為T的資源
⑵加載包內的多個資源
AssetBundle類
public Object[] LoadAllAssets(Type type);
加載包內所有類型為type的資源
public Object[] LoadAllAssets();
加載包內的所有資源
public T[] LoadAllAssets();
搞不懂,也是加載類型為T的資源
⑶備注,上面的方法是同步加載,還有異步加載方法
LoadAllAssetsAsync,LoadAssetAsync
3、從包內加載資源以后,可以對這個對象進行各種操作了
4、備注知識點
⑴Path.Combine(string, string) 連接兩個字符串
⑵ Application 訪問應用程序運行時數據
Application.streamingAssetsPath輸出
E:/UnityProject/ARVR/Workspace/MyCharacter/Assets/StreamingAssets
Application.dataPath輸出
E:/UnityProject/ARVR/Workspace/MyCharacter/Assets
值得注意的是如果在PC上使用時需要在每個文件夾前加入斜杠,如:
string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
例子:注意:加載要用協程,否則你不知道是否加載完畢
-
using UnityEngine;
-
using System.Collections;
-
using System.IO;
-
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;
-
}
-
//從Bundle包中加載名字為:MyObject的資源,加載為GameObject
-
var prefab = myLoadedAssetBundle.LoadAsset<GameObject>("MyObject");
-
//實例化
-
Instantiate(prefab);
-
//卸載包中資源的內存
-
myLoadedAssetBundle.Unload( false);
-
}
-
}
5、AssetBundle放在網絡
⑴創建一個UnityWebRequest,通過HTTP GET下載一個Unity資產包
引用using UnityEngine.Networking;命名空間
UnityWebRequest.GetAssetBundle()方法-
public static UnityWebRequest GetAssetBundle(string uri, uint crc);
-
-
public static UnityWebRequest GetAssetBundle(string uri, uint version, uint crc);
-
-
public static UnityWebRequest GetAssetBundle(string uri, Hash128 hash, uint crc);
-
-
public static UnityWebRequest GetAssetBundle(string uri, CachedAssetBundle cachedAssetBundle, uint crc);
返回值:UnityWebRequest
參數:
uri:AssetsBundle包的網絡地址:(可以是本地file:)
crc:0,如果不為0,將會進行校驗
version:一個整數版本號
hash:一個版本散列
cachedAssetBundle:用於將給定版本的AssetBundle下載到自定義緩存路徑的結構
⑵處理上一步的UnityWebRequest
用DownloadHandlerAssetBundle.GetContent()方法
public static AssetBundle GetContent(Networking.UnityWebRequest www);
www:就是上一步處理的UnityWebRequest
AssetBundle:返回值類型
例子
-
IEnumerator InstantiateObject()
-
-
{
-
string uri = "file:///" + Application.dataPath + "/AssetBundles/" + assetBundleName;
-
UnityEngine.Networking.UnityWebRequest request = UnityEngine.Networking.UnityWebRequest.GetAssetBundle(uri, 0);
-
yield return request.Send();
-
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
-
GameObject cube = bundle.LoadAsset<GameObject>( "Cube");
-
GameObject sprite = bundle.LoadAsset<GameObject>( "Sprite");
-
Instantiate(cube);
-
Instantiate(sprite);
-
}
六、完整例子
-
using System.Collections;
-
using System.Collections.Generic;
-
using UnityEngine;
-
using System.IO;
-
using UnityEngine.UI;
-
using UnityEngine.Networking;
-
public class NewBehaviourScript : MonoBehaviour {
-
-
Image image1;
-
Image Image2;
-
void Start () {
-
image1 = GameObject.Find( "Image (1)").GetComponent<Image>();
-
Image2 = GameObject.Find( "Image (2)").GetComponent<Image>();
-
StartCoroutine(InstantiateObject());
-
StartCoroutine(InstantiateObjects());
-
}
-
//一個包有多個資源
-
IEnumerator InstantiateObjects()
-
{
-
//texture是一個文件夾,里面放了多張圖片
-
string uri = "file:///" + Application.dataPath + "/AssetsBundles/texture";
-
UnityWebRequest request = UnityWebRequest.GetAssetBundle(uri, 0);
-
yield return request.Send();
-
AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
-
Object[] obj = bundle.LoadAllAssets( typeof(Sprite));
-
Sprite[] sprite = new Sprite[obj.Length];
-
for (int i = 0; i < obj.Length; i++)
-
{
-
sprite[i] = obj[i] as Sprite;
-
}
-
this.gameObject.GetComponent<Image>().sprite = sprite[0];
-
image1.sprite = sprite[ 1];
-
-
//string path = Application.dataPath + "/AssetsBundles/texture";
-
//AssetBundle assetbundle = AssetBundle.LoadFromFile(path, 0, 0);
-
//yield return assetbundle;
-
//if (assetbundle == null)
-
//{
-
// print("加載Bundle為空");
-
//}
-
//加載類型為sprite的圖片,否則一張圖片會加載成兩個
-
//Object[] obj =assetbundle.LoadAllAssets(typeof(Sprite));
-
//Sprite[] sprite = new Sprite[obj.Length];
-
//for (int i = 0; i < obj.Length; i++)
-
//{
-
// sprite[i] = obj[i] as Sprite;
-
//}
-
//this.gameObject.GetComponent<Image>().sprite = sprite[0];
-
//image1.sprite = sprite[1];
-
}
-
//一個包有一個資源
-
IEnumerator InstantiateObject()
-
{
-
//用UnityWebRequest讀取
-
//string uri = "file:///" + Application.dataPath + "/AssetsBundles/gress";
-
//UnityWebRequest request = UnityWebRequest.GetAssetBundle(uri, 0);
-
//yield return request.Send();
-
//AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(request);
-
//GameObject cube = bundle.LoadAsset<GameObject>("gress");
-
//Sprite sprite = bundle.LoadAsset<Sprite>("gress");
-
//this.gameObject.GetComponent<Image>().sprite = sprite;
-
-
//用AssetBundle讀取
-
string path = Application.dataPath + "/AssetsBundles/gress";
-
AssetBundle assetbundle = AssetBundle.LoadFromFile(path, 0, 0);
-
yield return assetbundle;
-
if (assetbundle == null)
-
{
-
print( "加載Bundle為空");
-
}
-
Sprite sprite = assetbundle.LoadAsset<Sprite>( "gress");
-
Image2.sprite = sprite;
-
}
-
-
// Update is called once per frame
-
void Update () {
-
-
}
-
}
七、AssetBundle Manager管理工具
AssetBundle Manage是一個管理AssetBundle的工具,在官方資源商店尋找
文檔說明
https://docs.unity3d.com/Manual/AssetBundles-Manager.html
下載地址
https://www.assetstore.unity3d.com/en/#!/content/45836
AssetBundle Manager是一個由Unity制作的工具,它可以使AssetBundle更加高效。
下載並導入AssetBundle Manager包不僅增加了加載和使用AssetBundle的新API,而且還添加了一些編輯器功能來簡化工作流。這個功能可以在Assets菜單選項下找到。八、備注
1、基於平台的加載AssetBundle方法
AssetBundle.LoadFromMemoryAsync
AssetBundle.LoadFromFile
WWW.LoadfromCacheOrDownload
UnityWebRequest DownloadHandlerAssetBundle(Unity 5.3 or newer)
方法:https://docs.unity3d.com/Manual/AssetBundles-Native.html
2、一些知識點網址
Unity5.X新版AssetBundle使用方案及策略
http://www.cnblogs.com/jiangshuai52511/p/6437239.html
Unity5新的AssetBundle系統使用心得
http://blog.csdn.net/langresser_king/article/details/44208585
[Unity熱更新]unity5中的assetbundle
http://blog.csdn.net/lyh916/article/details/49815871
3、下面的方法未經過測試,先記錄下來,待以后查詢
(1)、為需要打包到AssetBundle中的資源設置其assetBundleName,有兩種方式可以實現這個功能:一是手動在編輯界面對資源一一進行手動設置;二是遍歷需要設置的資源目錄,通過代碼動態設置。顯然第二個辦法更加方便,具體的步驟如下:
a.遍歷要打包的資源目錄,找到需要打包的預設或者資源;
b.設置資源的assetBundleName屬性;
c.通過AssetDatabase.GetDependencies(stringpath)方法逐個找到資源的依賴資源路徑;
d.使用AssetDatabase.AssetPathToGUID(stringpath)計算出每個資源的唯一ID,然后將此ID當做assetBundleName賦予每個依賴資源;
e.調用BuildPipeline.BuildAssetBundles(stringoutputPath)打包到指定位置。
(2).資源加載:
由於依賴關系存在於manifest中,所以加載資源之前,需要先加載manifest文件。