通常我们在游戏程式执行过程,并不希望一次将全部的资源都载入,而比较希望实际上有使用到的才载入,以免占用多余的记忆体,所以我们可能会尽量规划好不同功能的场景,在需要时才载入场景并释放掉前个场景中不需要的资源,或是将资源放在 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的更多相关文章

  1. Unity3D教程:无缝地形场景切换的解决方法

    http://www.unitymanual.com/6718.html 当我们开发一个大型项目的时候-会遇到这样的问题(地形场景的切换)这个只是字面意思-并不是重场景1的100  100 100坐标 ...

  2. (转)【风宇冲】Unity3D教程宝典之AssetBundles:第一讲

    自:http://blog.sina.com.cn/s/blog_471132920101gz8z.html 原创文章如需转载请注明:转载自风宇冲Unity3D教程学院                 ...

  3. (转)【风宇冲】Unity3D教程宝典之AssetBundles:第二讲

    原创文章如需转载请注明:转载自风宇冲Unity3D教程学院                             AssetBundles第二讲:AssetBundles与脚本 所有Unity的As ...

  4. Unity3D如何制作透贴和使用透贴模型

    http://momowing.diandian.com/post/2012-10-25/40040842845 Unity3D如何制作透贴和使用透贴模型??解决办法!!! 问题: 同事通过3DMAX ...

  5. (转)【风宇冲】Unity3D教程宝典之Blur

    原创文章如需转载请注明:转载自风宇冲Unity3D教程学院                   BlurBlur模糊其实理解了以后非常简单.核心原理就是 1个点的颜色 并不用该点的颜色,而是用该点周围 ...

  6. Unity3D教程宝典之Web服务器篇:(第三讲)PHP的Hello World

    转载自风宇冲Unity3D教程学院 引言:PHP是比较简单的编程语言,即使没接触过的也可以现学现用.PHP教程文档PHP100视频教程                           Unity接 ...

  7. Unity3D教程宝典之Web服务器篇:(第二讲)从服务器下载图片

    转载自风宇冲Unity3D教程学院                                    从Web服务器下载图片 上一讲风宇冲介绍了wamp服务器及安装.这回介绍如何从服务器下载内容至 ...

  8. Unity3D教程宝典之Web服务器篇:(第一讲)服务器的架设

    转载自风宇冲Unity3D教程学院 引言:本文主要介绍WAMP服务器的架设. 第一部分WAMP介绍;第二部分WAMP安装及使用.                        第一部分WAMP介绍 什 ...

  9. 【CityHunter】通过Unity3D来制作游戏中AR部分的内容

    嗯,最近再考虑,CityHunter中,玩家攻略藏宝图时,为了增加可玩性,应该增强在AR部分的游戏性.最近特别火的游戏<Pokemon Go>在打开摄像头以后,可以看到小精灵,实际上,如果 ...

随机推荐

  1. python调用php函数

    由于php不支持多线程,所以想借助python搞一个.1.import subprocessimport time#Simple caller, disguard outputmethod=" ...

  2. iOS 关于 Missing iOS Distribution signing identity for.... 等 打包 校验 出现的事故 处理经验

    着实郁闷了一阵子,不知道为什么 证书和配置文件都没有问题 在Archieve后  validate 提示:"Missing iOS Distribution signing identity ...

  3. Array排序方法sort()中的大坑

    sort() 方法用于对数组的元素进行排序. 但是排序结果就有点坑了,都不按常规出牌的: // 看上去正常的结果: ['Google', 'Apple', 'Microsoft'].sort(); / ...

  4. mysql多表查询原理

    转:https://www.cnblogs.com/Toolo/p/3634563.html MySQL的多表查询(笛卡尔积原理)   先确定数据要用到哪些表. 将多个表先通过笛卡尔积变成一个表. 然 ...

  5. level-8

    CSS选择器常见的有几种? !important选择器——它是所有选择器里面权重最高的. *选择器——它是所有选择器里面权重最低的.可以为页面所有的标签添加统一样式,多用于页面整体样式调整,但它会增加 ...

  6. python中类(class)和实例(instance)

    面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可 ...

  7. ⭐内核MKDEV(MAJOR, MINOR)宏

    版本:linux-2.6.24.4宏:    MKDEV(MAJOR, MINOR);  说明: 获取设备在设备表中的位置.        MAJOR   主设备号        MINOR   次设 ...

  8. Linux下解压分包文件zip(zip/z01/z02)

    分包压缩的zip文件不能被7z解压,且这种格式是Windows才能创建出来,在Linux下不会以这种方式去压包.下面是在Linux下处理这种文件的做法: 方法一: cat xx.z01 xx.zip ...

  9. 【转载】如何简单地理解Python中的if __name__ == '__main__'

    原帖:https://blog.csdn.net/yjk13703623757/article/details/77918633 通俗的理解__name__ == '__main__':假如你叫小明. ...

  10. java string 细节原理分析(2016.5)

    看到了以前2016.5月学习java写的笔记,这里放在一起. String实现的细节原理分析 一.jdk源码中String 的实现 public final class String implemen ...