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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 |
通常我们在游戏程式执行过程,并不希望一次将全部的资源都载入,而比较希望实际上有使用到的才载入,以免占用多余的记忆体,所以我们可能会尽量规划好不同功能的场景,在需要时才载入场景并释放掉前个场景中不需要的资源,或是将资源放在 Resource 资料夹中,在真正需要时才利用 Resources.Load() 把资源载入;这些都是不错的管理方法,但是当我们游戏中的资源相当多时,输出的程式还是会相当庞大,而且如果是时常会更新内容资源的游戏,也会因为庞大的资源而造成编译输出时要花相当多的时间;特别是手机或网页游戏,几乎输出最後的结果只是一个档案而已,这个档案如果很庞大,将可能造成下载或启动游戏的不方便;这时候我们可能就要考虑制作 AssetBundle。 制作与游戏主程式分离的资源包可以得到某程度上的好处,我们可以让游戏主程式只管理游戏逻辑的部份,当有需要某些资源则从外部的 AssetBundle 载入资源,这样一来,如果有任何游戏更新只是添加或更换资源,并没有变更到游戏程式逻辑或内容部署,我们只需要重新打包资源的部份就能完成更新,而不再需要整个游戏重新编译输出。 例如我们有已上架的 iPhone 游戏,因为特定节日想把游戏内的图片换成另一种气氛,通常就必须要重新输出,然後送审,等节日过後又想把图片换回原本的,要再次输出游戏,再送审,一方面送审费时费工,另一方面是从送审到架上游戏更新完成的时间,我们并不能准确掌控;如果事先将资源分离打包成 AssetBundle 储存在我们自己管理的伺服器中,在这种需要换图的时刻,只需要打包自行在伺服器中将 AssetBundle 更新即可,可以省掉不断送审的麻烦,时间上也更能掌控,另外就是游戏主程式中没有庞大的资源资料,主程式也就会小一点,那麽玩家要下载我们的游戏也会更快速些。 还有就是,我们输出为网页游戏时一定会发现到,输出结果只是一个 html 档及一个 unity3d 档,应该有写过网页的人都知道,网页的运作是浏览器将网页中的文件、图片、音乐、影像… 等等的资料下载到客户端暂存之後再执行呈现出结果,那麽如果我们游戏内容的庞大资源都与主程式编在一起的话,那麽输出後的 unity3d 档应该也会不小,此时我们可能要思考一下,我们希望玩家花多久时间完成启动页面再进行游戏呢?也许 Unity 的 Web Player 有办法解决这个问题使玩家不会花太多时间启动页面,但是正因为网页的运作方式是如此,所以当我们在伺服器端更新时,玩家只要没有重新载入页面,玩到的游戏内容始终是旧版的,此时又要考虑到,如果没有更新游戏逻辑或内容规则的情况下,是否有必要强制玩家中断游戏重新载入页面;如果将资源都打包成 AssetBundle 分离出来,那麽 unity3d 档这个主程式的部份将会变得更小,而当有任何资源更新时只需要在伺服器端将 AssetBundle 的档案换掉,玩家不需要重新载入页面一样能体验到更新後的内容。 以上主要说明 AssetBundle 是个很重要又好用的东西,毕竟在没变更程式或游戏部署的情况下,没必要去重新 Build 游戏主程式,以下就来说明如何制作 AssetBundle … 首先要自定义选单命令,使我们能够操作何时开始制作 AssetBundle 及如何做,接下来我们需要能够指定哪些资源将打包成 AssetBundle,所以需要使用到 Editor class
的 Selection.GetFiltered(),还有就是要过滤哪些型别的资源才是我们要的,选择错误则略过,不要处理,最後再使用 BuildPipeline.BuildAssetBundle() 建立 AssetBundle 即可,以下范例会在 Unity 专案资料夹(不是 Asset 资料夹)中建立 _AssetBunldes 资料夹用来存放打包好的 AssetBundle,打包的目标为 GameObject、Texture2D、Material 三种型别的资源,如果储存档案路径档名相同则会先删除旧档: [MenuItem( "Custom Editor/Create AssetBunldes" )] static
void ExecCreateAssetBunldes(){ // AssetBundle 的資料夾名稱及副檔名 string
targetDir = "_AssetBunldes" ; string
extensionName = ".assetBunldes" ; //取得在 Project 視窗中選擇的資源(包含資料夾的子目錄中的資源) Object[] SelectedAsset = Selection.GetFiltered( typeof
(Object), SelectionMode.DeepAssets); //建立存放 AssetBundle 的資料夾 if (!Directory.Exists(targetDir)) Directory.CreateDirectory(targetDir); foreach (Object obj in
SelectedAsset){ //資源檔案路徑 string
sourcePath = AssetDatabase.GetAssetPath(obj); // AssetBundle 儲存檔案路徑 string
targetPath = targetDir + Path.DirectorySeparatorChar + obj.name + extensionName; if (File.Exists(targetPath)) File.Delete(targetPath); if (!(obj is
GameObject) && !(obj is
Texture2D) && !(obj is
Material)) continue ; //建立 AssetBundle if (BuildPipeline.BuildAssetBundle(obj, null , targetPath, BuildAssetBundleOptions.CollectDependencies)){ Debug.Log(obj.name + " 建立完成" ); } else { Debug.Log(obj.name + " 建立失敗" ); } } } 以上是直接将选择的资源打包成 AssetBundle,另外,你也可以在打包前依需求将型别为 GameObject 的资源 Instantiate 到场景中添加需要的 Component 并回到 Project 中建立 Prefab,最後再以这个 Prefab 打包成 AssetBundle,一切就看个人如何运用了。 制作好的 AssetBundle 最终目的还是要在游戏中载入,以下用简短的范例在游戏画面上显示一个按钮,当按下按钮之后载入型别为 GameObject 的 AssetBundle 并利用 Instantiate() 使其实例化而在场景中产生 GameObject: void
OnGUI(){ if (GUI.Button( new
Rect(5,35,100,25) , "Load GameObject" )){ StartCoroutine(LoadGameObject()); } } private
IEnumerator LoadGameObject(){ // AssetBundle 檔案路徑 string
path = string .Format( "file://{0}/../_AssetBunldes/{1}.assetBunldes"
, Application.dataPath , "TestGameObject" ); // 載入 AssetBundle WWW bundle = new
WWW(path); //等待載入完成 yield
return bundle; //實例化 GameObject 並等待實作完成 yield
return Instantiate(bundle.assetBundle.mainAsset); //卸載 AssetBundle bundle.assetBundle.Unload( false ); } 范例中的档案路径(path)字串是以此程式码在 Unity 编辑器中执行为例,实作时应该以实际执行平台及个人喜好指定 AssetBundle 存放路径,详情可参考官方文件 Application.dataPath 说明;因为载入的资源必须要等待载入完成以确保游戏运作正常,在 C# 使用 yield 除了回传型别为 IEnumerator 之外,调用时也必须使用 StartCoroutine() 调用,如果使用 Javascript 则可直接呼叫该 function;如果 AssetBundle 已载入过,下次再请求载入将会出现 [The asset bundle ‘档名 ‘ can‘ t be loaded because another asset bundle with the same files are already loaded]的错误讯息,即使使用区域变数(范例中的 bundle)仍然会得到这个错误讯息,所以必须在每次载入使用完后将 AssetBundle 卸载;另外,要特别注意的是载入 AssetBundle 到卸载期间可能消耗些微时间,如果连续调用载入同一个 AssetBundle,造成在卸载前重复载入也可能出现前面的错误讯息,所以,最好是能定义个阵列或其它变数来记录载入中的 AssetBundle 有哪些,以此变数内容在载入 AssetBundle 前检查。 |
Unity3D教程:制作与载入AssetBundle,布布扣,bubuko.com
原文:http://www.cnblogs.com/hewei2012/p/3779134.html