您的位置:首页 > 移动开发 > Unity3D

Unity热更新系列之AssetBundle(1) ——详述如何设置AssetBundle Name

2018-01-20 17:49 781 查看

Unity热更新系列之AssetBundle(1)

——详述如何设置AssetBundle Name

在打资源包前,需要为资源设置AssetBundle名,该资源名称除了包含自己的名字外,还应该包含该资源在整个资源文件夹下的子目录层级。

如下:texture是该资源在整个大文件夹下的分类文件夹。



当设置了分类文件夹后,打出的资源会自动将该文件分类到这个文件夹下

可以用AssetImporter.assetBundleName对该名称进行设置:

//path是该资源相对Asset下的路径
AssetImporter.GetAtPath(path).assetBundleName = 分类文件夹+  name;


在游戏资源中,存在资源相互引用的现象。

比如一个NGUI图集,会引用一个材质和一个UIAtlas.cs脚本,其中材质球上又会引用一个Texture和一个Shader。

我们可以在Project窗口中右键点击图集的预制体,点击上面的 Select Dependencies 来选中这个图集的所有依赖。

如图:





这里能看到该图集所引用的所有对象。其中的1个Game Object其实就是我们选中的图集预制体本身。1个 MonoScript 就是该预制体上挂在的NGUI组件 UIAtlas.cs脚本,在Unity中,脚本文件无法当做资源文件,也没有AssetBundleName。

其他资源Inspector窗口的最下面都有AssetBundleName属性,而脚本是没有的。

设置AssetBundleName时,有两种方式:

一是当我们为除了脚本外的4个物体,分别设置AssetBundle Name,打出的资源中,会将这四个资源分开打成4个AssetBundle文件。

这时我们在游戏中加载AssetBundle文件时,就必须先拿到该文件的引用关系,按照引用关系将所有引用到的AssetBundle文件都加载进内存,才可以正常使用。

二是只对图集的预制体设置AssetBundle Name,则会将其引用的所有资源全都打成1个AssetBundle文件。

这时我们在游戏中加载AssetBundle文件时,只需要加载我们需要的资源文件就可以了,省略了处理引用的步骤。

对比上述两种制作AssetBundle的方法。

第一种在游戏中多了一步引用的处理,但是打出来的资源重复率是最低的,对减少游戏安装包大小会有一定的作用。但是经常会因为一个资源文件的问题而引起其他所有引用该资源的文件都出现问题。

第二种,资源会重复打进AssetBundle中,比如一个Shader,被10个图集资源引用,会导致该Shader被重复打10次。但是在游戏加载的逻辑中,不需要再次处理引用。

两种方式该如何选择呢?

首先,使用第一种方式打一次资源





接着,我们用第二种方式打一遍资源。



打出的资源中,主要包括资源文件本身,和每个资源文件都会有的manifest文件(记录资源文件的信息和引用依赖关系),还有就是 .meta文件,是Unity在运行时自动生成的,不影响我们要讨论的问题。

我们真正需要注意的,是UNITY3D文件,可以看到,第二种方式打出的图集大小是339KB,第一种打出的图集分成了四个UNITY3D文件,其中最大的是Texture文件,占用了335KB,剩下的图集预制体2KB,材质2KB,shader 3KB,总计341KB,算下来比第二种方式还大了3KB,这是因为每个AssetBundle文件中除了资源本身的字节外,Unity还会在生成AssetBundle时,在里面添加一些字节,记录一些Unity处理该AssetBundle时需要用到的信息。对于这些字节,第二种方式只需要添加一次,而第一种添加了4次。

但是如果有10个图集,它们引用了同一个材质和Shader,用第一种方式,每次都能少打5KB。这样算下来,还是能比第二种节省一些。

图集引用到的资源中,最大的应该是材质球上面引用的Texture,但是 Texture 对于每个图集都是唯一的,不会重复引用。相比之下,重复引用的材质和Shader的大小可以忽略不计。

再来对比一下相应的manifest文件。

第一种:

我们先看一下预制体的manifest文件



其中1表示它引用了一个材质文件,2表示它引用了一个脚本类组件。

注:

前面已经说过脚本类文件是不能打资源的,所以对于预制体上面挂载的脚本,会在AssetBundle中记录它所引用的脚本的guid,在程序运行时,在程序中找到该guid对应的脚本挂载在从AssetBundle中加载出的Gameobject上。

此时挂载的脚本逻辑可以和打AssetBundle时挂载的脚本逻辑不一样,但是可以用来传递参数,利用该特性可以做很多事!

举个例子:

美术制作特效时,我们可以给他们一个脚本,里面只定义一个变量,特效销毁时间

public class EffectControl : MonoBehaviour {
public float DestoryTime;

private float startTime;
private void OnEnable()
{
startTime = Time.realtimeSinceStartup;
}
private void Update()
{
if (Time.realtimeSinceStartup - startTime > DestoryTime)
{
Destroy(gameObject);
}
}
}


这样处理我们就可以拿到美术中给的变量DestoryTime,来执行真正的逻辑。

再来看一下材质对应的manifest文件



这里记录了该材质引用了一个Shader文件和一个Texture文件。

第二种:



我们发现对于第二种方式打出来的资源,其依赖信息为空,证明了它没用引用任何其他资源,所有的资源全都打成了一个AssetBundle。

这样我们可以得出结论,对于资源文件,也应该优先考虑这个资源引用的其它资源共同引用的资源部分的大小,如果这部分本身就不大,真正的大头资源(比如图集中的Texture)又是唯一的,那就没有必要使用第一种资源加载方式,建议直接使用第二种资源加载方式。

本文中使用到的图集Atlas下载地址
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息