Unity3D教程:制作与载入AssetBundle
通常我们在游戏程式执行过程,并不希望一次将全部的资源都载入,而比较希望实际上有使用到的才载入,以免占用多余的记忆体,所以我们可能会尽量规划好不同功能的场景,在需要时才载入场景并释放掉前个场景中不需要的资源,或是将资源放在 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的更多相关文章
- Unity3D教程:无缝地形场景切换的解决方法
http://www.unitymanual.com/6718.html 当我们开发一个大型项目的时候-会遇到这样的问题(地形场景的切换)这个只是字面意思-并不是重场景1的100 100 100坐标 ...
- (转)【风宇冲】Unity3D教程宝典之AssetBundles:第一讲
自:http://blog.sina.com.cn/s/blog_471132920101gz8z.html 原创文章如需转载请注明:转载自风宇冲Unity3D教程学院 ...
- (转)【风宇冲】Unity3D教程宝典之AssetBundles:第二讲
原创文章如需转载请注明:转载自风宇冲Unity3D教程学院 AssetBundles第二讲:AssetBundles与脚本 所有Unity的As ...
- Unity3D如何制作透贴和使用透贴模型
http://momowing.diandian.com/post/2012-10-25/40040842845 Unity3D如何制作透贴和使用透贴模型??解决办法!!! 问题: 同事通过3DMAX ...
- (转)【风宇冲】Unity3D教程宝典之Blur
原创文章如需转载请注明:转载自风宇冲Unity3D教程学院 BlurBlur模糊其实理解了以后非常简单.核心原理就是 1个点的颜色 并不用该点的颜色,而是用该点周围 ...
- Unity3D教程宝典之Web服务器篇:(第三讲)PHP的Hello World
转载自风宇冲Unity3D教程学院 引言:PHP是比较简单的编程语言,即使没接触过的也可以现学现用.PHP教程文档PHP100视频教程 Unity接 ...
- Unity3D教程宝典之Web服务器篇:(第二讲)从服务器下载图片
转载自风宇冲Unity3D教程学院 从Web服务器下载图片 上一讲风宇冲介绍了wamp服务器及安装.这回介绍如何从服务器下载内容至 ...
- Unity3D教程宝典之Web服务器篇:(第一讲)服务器的架设
转载自风宇冲Unity3D教程学院 引言:本文主要介绍WAMP服务器的架设. 第一部分WAMP介绍;第二部分WAMP安装及使用. 第一部分WAMP介绍 什 ...
- 【CityHunter】通过Unity3D来制作游戏中AR部分的内容
嗯,最近再考虑,CityHunter中,玩家攻略藏宝图时,为了增加可玩性,应该增强在AR部分的游戏性.最近特别火的游戏<Pokemon Go>在打开摄像头以后,可以看到小精灵,实际上,如果 ...
随机推荐
- Github结合Eclipse出现的问题
半年前因为学习Git花费了很长时间,半年过去了,因为不使用,基本全部忘记了,最近在公司需要使用Eclipse开发相关项目,用到前期的测试数据挖掘的小算法,又重拾Git,不过这次不再是命令行模式,而是结 ...
- g高分屏DataGrid里面checkbox不显示的解决办法
- Shell编程之运算
一.变量的数值计算 1.算术运算符 常用的运算符号 常用的运算命令 (1)双小括号 基本语法 1)利用"(())"进行简单运算 [root@codis-178 ~]# echo $ ...
- 仿Facebook登录表单
在线演示 本地下载
- 优美的英文诗歌Beautiful English Poetry
<When you are old>——<当你老了> --- William Butler Yeats ——威廉·巴特勒·叶芝When you are old and grey ...
- Kubernetes Headless Service
1. Headless Service headless service 需要将 spec.clusterIP 设置成 None. 因为没有ClusterIP,kube-proxy 并不处理此类服务, ...
- 多校hdu5726 线段树+预处理
第一问是没有修改的线段树,第二问暴力预处理,因为gcd的结果不会很多 在预处理阶段需要把每个区间的gcd相等的数量储存起来(用map容器),在一个序列例如:12467,枚举左区间L直到n此处时间为O( ...
- 泛型学习第一天:List与IList的区别 (三)
已经有很多人讨论过IList和List的区别,恩,我也赞同其中的一些观点,其实他们二者也是有优有劣的,看你着重用在哪个方面,先贴一下我赞同的意见,基本上也都是网友们总结的. 首先IList 泛型接口是 ...
- 关于hadoop setCombinerClass 与 setReducerClass同时使用存在的问题。
最近在学习hadoop mapreduce编程的过程中遇到一个莫名奇妙的问题.最后通过调试时发现同时使用setCombinerClass(Reducer.class) 与 setReducerCl ...
- JBOSS invoker GETSHELL(PHP版)
<?php $target = @$argv[1]; $procotol = @$argv[2]; if ($argc < 2) { print "[-]:php Jboss.p ...