unityunity5 assetbundlee 加载场景不能超多少

Unity中资源动态加载的两种方式之AssetsBundle
Unity中资源动态加载的两种方式之AssetsBundle
001.Load脚本,挂载到摄像机上&pre name="code" class="csharp"&using UnityE002.using System.C003.using UnityE004.&005.public class Build : MonoBehaviour006.{007.&&&&// 编辑器类008.&&&&[MenuItem("Build/BuildAsset")]009.&&&&// 打包单个资源的方法010.&&&&static void BuildAsset ()011.&&&&{012.&&&&&&&&// 将物体打包到/AssetsBundles路径下同时命名为Cube1.assetbundle013.&&&&&&&&string targetPath = Application.dataPath + "/AssetsBundles/Cube1.assetbundle"; 014.&&&&&&&&// BuildPipeline 打包用 Selection (Selection.activeObject 在编辑器中选中的对象)015.&&&&&&&&// 第二个参数null,是打包多个资源的时候用的,多个资源就是数组,单个资源的时候这个参数不用写016.&&&&&&&&// 第三个参数是路径,你想把这个资源放到什么位置就写什么,并且还要命名为.assetbundl格式017.&&&&&&&&BuildPipeline.BuildAssetBundle (Selection.activeObject, null, targetPath);018.&&&&&&&&// 刷新资源,直接可以在unity中看到刚才打包的东西019.&&&&&&&&AssetDatabase.Refresh();020.&&&&}021.&022.&&&&// --------------------------------------------------------------------------------023.&024.&025.&&&&[MenuItem("Build/BuildMultiAsset")]026.&&&&// 打包多个资源的时候使用这个方法027.&&&&static void BuildMultiAsset()028.&&&&{029.&&&&&&&&// 将物体打包到/AssetsBundles路径下同时命名为Cubes.assetbundle030.&&&&&&&&string target = Application.dataPath + "/AssetsBundles/Cubes.assetbundle";031.&&&&&&&&// 因为打包多个游戏对象,所以是一个数组,typr(Object)表示,只要选择的物体是Object类型就可以032.&&&&&&&&// 并且选择的模式是深度资源搜索(具体学名到底叫啥我也忘了。。。),033.&&&&&&&&// 意思是只要你选择的object对象下面如果还有关联的东西就都会一起打包(unity导出场景的时候应该可以感受到)034.&&&&&&&&Object[] cubes = Selection.GetFiltered(typeof(Object),SelectionMode.DeepAssets);035.&&&&&&&&// 打包开始,因为是一堆资源,所以主资源为null,剩下两个参数意思同上036.&&&&&&&&BuildPipeline.BuildAssetBundle(null,cubes,target);037.&&&&&&&&// 刷新资源,直接可以在unity中看到刚才打包的东西038.&&&&&&&&AssetDatabase.Refresh();039.&&&&}040.&041.&&&&// --------------------------------------------------------------------------------042.&043.&&&&[MenuItem("Build/BuildScene")]044.&&&&// 打包场景的方法045.&&&&static void BuildScene()046.&&&&{047.&&&&&&&&// 场景名字,为什么是数组呢(因为参数里要求这个参数是数组类型。。。。)048.&&&&&&&&string [] sceneName =& new string[]{Application.dataPath + "/scene1.unity"};049.&&&&&&&&// 将物体打包到/AssetsBundles路径下同时命名为Scene1.assetbundle050.&&&&&&&&string targetPath = Application.dataPath + "/AssetsBundles/Scene1.assetbundle";051.&&&&&&&&// 注意打包的方法名已经变成流类型了,后面的最后一个参数表示你要在上面平台运行052.&&&&&&&&// iphone平台就是用BuildTarget.iPhone这个参数053.&&&&&&&&// 安卓平台就是用BuildTarget.&a href="" target="_blank" class="keylink"&Android&/a&这个参数054.&&&&&&&&// 类似参数可以自己查看。。。055.&&&&&&&&BuildPipeline.BuildStreamedSceneAssetBundle(sceneName,targetPath,BuildTarget.WebPlayer);056.&&&&&&&&// 刷新资源,直接可以在unity中看到刚才打包的东西057.&&&&&&&&AssetDatabase.Refresh();058.&&&&}059.&&&&// --------------------------------------------------------------------------------060.&&&&[MenuItem("Build/BuildDependence")]061.&&&&static void BuildDependence()062.&&&&{063.&&&&&&&&// 对一些公共参数的定义 //064.&&&&&&&&// 定义路径文件夹是Application.dataPath读取后的路径 加上 "/AssetBundles"065.&&&&&&&&string path = Application.dataPath + "/AssetsBundles";066.&&&&&&&&// 定义资源包的依赖关系选项067.&&&&&&&&BuildAssetBundleOptions buildOp = BuildAssetBundleOptions.CollectDependencies | pleteA068.&069.&&&&&&&&// ---------------------------------------------------------------------070.&071.&&&&&&&&// Push和Pop是成对出现的,他们的作用是维持一个依赖关系072.&&&&&&&&// 我们当前的资源包关系是这样的:073.&&&&&&&&/*074.&&&&&&&&&&&&Tex1.assetbundle资源包(Tex1的包里有以下2个资源包)075.&&&&&&&&&&&&&&&&c1.assetbundle资源包(c1和c2是平级关系)076.&&&&&&&&&&&&&&&&c2.assetbundle资源包&& 077.&&&&&&&&*/078.&&&&&&&&//依赖资源压栈079.&&&&&&&&BuildPipeline.PushAssetDependencies();080.&081.&&&&&&&&// 替代之前的selection的手动选择方式082.&&&&&&&&Object tex = AssetDatabase.LoadMainAssetAtPath("Assets/Resources/Tex1.jpg");083.&084.&&&&&&&&// 所有后续资源将共享这一资源包中的内容,但是你要保证的是,在使用c1和c2这种内层依赖包时085.&&&&&&&&// 你已经加载了最外层资源包Tex1086.&&&&&&&&BuildPipeline.BuildAssetBundle(tex, null,path + "/Tex1.assetbundle", buildOp);087.&088.&&&&&&&&// 这里使用一对Push和Pop是将我们接下来加载的c1资源包和tex依赖起来089.&&&&&&&&BuildPipeline.PushAssetDependencies();090.&&&&&&&&Object c1 = AssetDatabase.LoadMainAssetAtPath("Assets/Resources/Cube1.prefab");091.&&&&&&&&BuildPipeline.BuildAssetBundle(c1, null, path + "/c1.assetbundle", buildOp);092.&&&&&&&&BuildPipeline.PopAssetDependencies();093.&094.&&&&&&&&// 同上095.&&&&&&&&BuildPipeline.PushAssetDependencies();096.&&&&&&&&Object c2 = AssetDatabase.LoadMainAssetAtPath("Assets/Resources/Cube2.prefab");097.&&&&&&&&BuildPipeline.BuildAssetBundle(c2, null,path + "/c2.assetbundle", buildOp);098.&&&&&&&&BuildPipeline.PopAssetDependencies();099.&100.&&&&&&&&// 依赖资源出栈101.&&&&&&&&BuildPipeline.PopAssetDependencies();102.&&&&&&&&AssetDatabase.Refresh();103.&&&&}104.&105.&106.}
发表评论:
馆藏&20612
TA的推荐TA的最新馆藏[转]&[转]&[转]&[转]&[转]&[转]&[转]&[转]&[转]&[转]&unity 基于Assetbundle的更新机制的设计 - 为程序员服务
unity 基于Assetbundle的更新机制的设计
客户端资源的管理是一个复杂的问题,这里描述一下我的一些实践:
一:早期的cocos2dx项目中,
资源之间的依赖关系是写在代码里面的,资源的拼接组装都是通过代码进行的,因此游戏更新,主要通过两个途径,即代码更新和图片的更新;
cocos2dx 支持多个优先级的资源获取,即从高优先级目录或者位置首先搜索资源,没有的话再去低优先级位置搜索资源,这样sd卡上下载的新资源就会比apk中的旧资源优先加载,而只需要更新sd中资源即可;
我对所有资源做了一个md5值,客户端首先下载md5文件,和本地md5版本比较,找出新加的和更新的文件,挨个下载,最后再更新md5文件即可。
上述的方案存在问题:
1:资源之间的依赖关系被嵌入到代码中了,对应简单的2d游戏基本是图片拼接,依赖管理比较简单,可以这样处理
2:资源缺少整合打包机制,逐个下载和加载资源效率不高,不过2d游戏还是可以容忍的,好处就是资源管理简单,资源更新非常灵活
二:unity中资源更新机制
1:unity中资源在编辑器中可以通过guid定位资源并且编辑资源的依赖关系,最后固化到prefab中;最后整个项目的资源就构成 多棵树木, 树木的root根节点都放在 Resource目录下,而树木的root所依赖的资源放到 Resources目录外即可。
unity中这种资源依赖关系,可以从Resource目录中资源开始分析,最后就可以得到所有的依赖关系。
2:unity 中可以将多个资源打成一个assetbundle,接着游戏通过块加载的方式提高加载速度;这里就存在一个严重的问题,即如何在内存使用和加载速度之间取得平衡呢?当内存不够加载所有的游戏资源怎么办?
如果内存可以放下所有的assetbundle,那么只需要全部加载即可,也就没有后面的问题了。
assetbundle对客户端来讲是静态资源集合,无法对资源进行拆分和重组织,因此其对应的游戏机制一般也是静态资源集合的方式,例如最常见的关卡场景模型,单种场景类型的资源是可以整合一起加载的。
当内存不足,则需要分类资源,对资源进行规划了。
资源分为公共资源和特殊使用资源,以及介于两者之间的资源,需要分别控制两种资源的规模。
其中公共资源需要为场景特殊资源预留足够的内存。
在假想的规划设计中,公共资源即常驻内存资源最多不超过规划内存总量的50%,而场景资源则占用剩余的40%。
接着是一些零散的碎片资源,这些资源的使用介于公共资源和场景独占资源之间,即有一定的跨场景使用能力,但这种能力应该要设计低于50%。
通过上面三种分类,接着设计如何分类assetbundle。
方案一:所有资源一个 assetbundle,需要设计游戏内容完全可内存承载。
方案二:最简单的分类方法,即每个单一资源对应一个assetbundle即类似于cocos2d中最灵活的方案。
方案三:多包机制,资源分类从来都不是个简单问题
高级方案则需要对资源分类,采取合适的整合方法:
如果构建合适的规则来对资源进行分类整合呢?
这里采用人工分类和实践自动分析结合的方式:
首先资源的Root 树结构分析可以找到最终的叶子资源;这些资源是无依赖资源,存在多种资源对其有需求,例如一个shader资源,可能有多个材质都需要使用;这种资源很有可能是属于公用资源的,例如其使用率高于50%即可认为是公用资源,例如UI资源。
其它一些叶子节点特殊属于某类场景,则从叶子节点向上都应该属于某个场景,类似的,只要我们确定某个节点特属于特定场景,则该节点所有父亲节点也特属于某个场景。则根据场景打包。
相反的我们有,若某个节点多场景使用,则其所有孩子节点也是多场景使用节点。
三:游戏资源的更新
对应于上面分的3类:
其中Common资源会添加,但是更新频率应该要控制较低,COmmon中UI类又属于高频度更新,应该尽量控制使用现有资源制作新的UI,而不是添加新的资源。shader资源也属于公用性资源,特殊针对某个模型的shader除外。
而场景独占资源是对游戏内容的扩充,频繁更新;
跨场景资源,流动性中等,推荐采用单资源单assetbundle模式,例如新的职业角色,新的怪物等。
四:后期如何调整资源分类,如何更新资源
资源分类应该有一种自适应的方案来进行,随着游戏发展而逐渐调整;
我们添加一个资源到树中,根据资源所处的父亲和孩子节点,得出资源倾向于和父亲属于同一个包便于一起加载,否则需要加载两个包,若父亲包过大 则资源倾向于和所有父亲包中资源的孩子构成的兄弟构成一个新包;
若孩子包过大,则资源可以独立成包。
这种结构保证了不会发生沉降现象,即父亲包 沉入孩子组中。
五:所有问题的关键还是
公共资源规模控制;
场景特殊资源规模控制;
游动资源规模控制
李勇2的博客
原文地址:, 感谢原作者分享。
您可能感兴趣的代码温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
我是阿赵,请多多指教!
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
http://liweizhaolili./blog/static// 先来说说关于旧版本的AssetBundle的事情。 之前我写了一个批量导出AssetBundle的小插件,有朋友留言说我没有解决依赖关系。后来在一位同事的指导下,我终于把这个问题搞清楚了,其实说白了过程就是先扫描所有要打包的资源,然后用AssetDatabase.GetDependencies获得所有的依赖,自己记录起来,由于怕资源之间有重名的,所以最好用AssetDatabase.AssetPathToGUID获得资源的唯一id,然后存起来。获得了所有依赖关系之后,再使用BuildPipeline.PushAssetDependencies和BuildPipeline.PopAssetDependencies按照层级和顺序来打包。这样打出来的资源就完全的保留了依赖关系,文件也拆得很散很小,不会重复打包了。 在加载的时候,由于我们是预先记录了各个资源的依赖关系,所以在加载某一个资源的时候,先去保存的文件里面查找它的依赖关系,把所有用到的依赖资源都先加载一次,然后再加载它,就能完整的加载出一个想要的模型之类了。 这就是完整的旧版本AssetBundle依赖打包和加载的流程了。不过由于是受人指导学会的,所以不方便把全部代码贴出来。 再来看看5.0版本的心AssetBundle的使用情况: 看到新版本的AssetBundle,我那位同事估计会一口老血喷在屏幕上面。那是因为,这个辛辛苦苦做出来的打包策略,Unity已经集成了。 新版本的AssetBundle在打包的时候多了一个叫做BuildPipeline.BuildAssetBundles(outputPath)的方法,然后每一个资源可以设置一个assetBundleName。只要你调用这个方法,那么所有已经设置过assetBundleName的资源,就会自动打包,具体的好处有:1、可以直接在编辑器UI上设置操作2、提供了更简便的脚本API3、Unity本身会处理所有的依赖关系4、生成了一种叫做manifest的文件,用于记录资源之间的依赖关系,并以链式结构记录,修改时只需修改链的其中一环5、增量打包功能。以上的好处,是官方说明的,我大概操作了一下,说的都是事实,只是使用时有点需要注意的地方。 很明显的看出,这些优点,正是我那位同事已经做过的事情,和一些暂时没有做到的事情。 先来说说最多人关心的问题,Unity自己处理依赖关系。 实际上来说,所有需要打包成AssetBundle的资源,你是要先赋予它一个assetBundleName的,在它有了assetBundleName之后,实际上它的信息已经存在于AssetDataBase里面了。所以在打包的时候,只需要调用BuildPipeline.BuildAssetBundles方法,它会把记录了的在AssetDataBase里面的所有资源先计算出依赖关系,再拆分打包。这个步骤是一点问题都没有的。要注意的是,你所有依赖的资源都必须赋予assetBundleName,不然,依赖就不会被拆分。 在加载的时候,AssetBundle的特性是和旧版本一样的,就是当一个目标资源的依赖资源已经存在与内存中(也就是已经被加载过了),那么在加载目标资源的时候,Unity会自动的帮你找到依赖关系。所以在加载的时候实际上还是要你手动加载依赖资源的。这一点和旧版本一样。 再来说说打包工具的编写。 虽然官方说得很美好,一句BuildPipeline.BuildAssetBundles(outputPath)就可以直接把所有资源都打包了,而需要打包的资源可以在编辑器界面直接输入。但实际上由于上面说到的必须赋予每一个依赖资源assetBundleName,你不可能每一个资源去手动的查找用到的依赖资源再在编辑器输入名字,所以旧版本的打包流程还是要的。 首先,你可以遍历需要打包的文件夹,把所有需要打包的预设或者资源都找到,然后设置assetBundleName,然后,通过AssetDatabase.GetDependencies方法逐个找到资源的依赖资源路径,用AssetDatabase.AssetPathToGUID算出每个资源的唯一ID,然后将唯一ID当做assetBundleName赋予给每个依赖资源。最后,调用BuildPipeline.BuildAssetBundles(outputPath)打包到指定位置。 最后说说加载。 由于依赖关系都存在于manifest中,所以在加载资源之前,要先加载manifest文件。 实际上在打包的时候,会有一个总的manifest文件,叫做AssetBundle.manifest,然后每一个小的资源分别有一个自己的manifest文件。在我们加载的时候,需要先把总的AssetBundle加载进来。比如这样:& & & & string mUrl = Cdn + "AssetBundle";& & & & WWW mwww = WWW.LoadFromCacheOrDownload(mUrl, 0);& & & && & & & if (!string.IsNullOrEmpty(mwww.error))& & & & {& & & & & & Debug.Log(mwww.error);& & & & }& & & & else& & & & {& & & & & & AssetBundle mab = mwww.assetB& & & & & & AssetBundleManifest mainfest = (AssetBundleManifest)mab.LoadAsset("AssetBundleManifest");& & & & & & mab.Unload(false);其中Cdn是我的资源路径,加载完之后,得到了一个AssetBundleManifest&对象。然后根据我们需要加载的资源名称,获得所有依赖资源:& & & & & & string[] dps = mainfest.GetAllDependencies(realName);& & & & & & AssetBundle[] abs = new AssetBundle[dps.Length];& & & & & & for (int i = 0; i & dps.L i++)& & & & & & {& & & & & & & & string dUrl = Cdn + dps[i];& & & & & & & & WWW dwww = WWW.LoadFromCacheOrDownload(dUrl, mainfest.GetAssetBundleHash(dps[i]));& & & & & & & && & & & & & & & abs[i] = dwww.assetB& & & & & & }其中realName是想加载的AssetBundle的名字,需要带扩展名。通过了这一步,所有的依赖资源都加载完了,可以加载目标资源了:&WWW www = WWW.LoadFromCacheOrDownload(url, mainfest.GetAssetBundleHash(realName+".ab"), 0);& & & & & && & & & & & if (!string.IsNullOrEmpty(www.error))& & & & & & {& & & & & & & & Debug.Log(www.error);& & & & & & }& & & & & & else& & & & & & {& & & & & & & & AssetBundle ab = www.assetB& & & & & & & & GameObject gobj = ab.LoadAsset(realName) as GameO& & & & & & & & if (gobj != null)& & & & & & & & & & Instantiate(gobj);& & & & & & & & ab.Unload(false);& & & & & & }& & & & & & foreach (AssetBundle ab in abs)& & & & & & {& & & & & & & & ab.Unload(false);& & & & & & }到这一步,所有的资源都加载完毕了。注意的是,记得Unload,不然下次就加不进来了。或者不Unload的话,就做一个字典记录所有加载过的AssetBundle,还有它们的引用计数器。那样就可以先判断是否存在在加载。
以上就是Unity5.0的AssetBundle的使用方法了。下面来吐槽一下。1、看Unite2014大会的视频介绍时,感觉这个东西真好,提供了这么强大的功能和这么简单的API。但实际用过之后,发现整个打包和加载的过程其实和旧版差不多,真正有意义的功能,是manifest的链式结构,和增量打包功能。2、我在没有使用之前,以为可以按照文件夹结构来打包,那样的话,就可以简单的从Resources.Load和外部WWW加载中做切换,只需要替换一个CDN地址就可以了。但实际上Unity把所有AssetBundle都打包在了同一个目录,在这个转换的过程中,我们还需要记录一下两者的对应关系。(其实这一点是错误的,assetName只要是带“/”的,就能自动生成文件夹结构的,之后的文章都忘记提了,误导了大家)3、资源打包的策略有时候和项目的设计本身有关,如果是阶段性很明确的资源管理,可能旧版的AssetBundle打包也不错。4、现在只看了Unity5的AssetBundle觉得不错,但又看了一下其他功能,发现Unity5的很多功能都改了,这样的大改动对于旧项目来说有可能是影响非常大的,是不是值得为了新的AssetBundle而升级Unity,还是需要更多的评估。
阅读(42447)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_',
blogTitle:'Unity5的AssetBundle的一点使用心得',
blogAbstract:'\t昨天一位朋友在我这里留言,想让我写点Unity5的AssetBundle心得。于是我就看了相关的介绍,和自己确切的做了一次。下面来谈谈所谓的心得。\t如果你觉得自己对AssetBundle不熟悉,建议先看看另外一篇文章:http://liweizhaolili./blog/static//\t先来说说关于旧版本的AssetBundle的事情。',
blogTag:'unity5,assetbundle',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:7,
publishTime:8,
permalink:'blog/static/',
commentCount:115,
mainCommentCount:31,
recommendCount:1,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'我是阿赵,请多多指教!',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}

我要回帖

更多关于 unity5 assetbundle 的文章

 

随机推荐