U4S4L3——指定资源加载

本章代码关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//不同的资源加载标识类
AssetReference //通用资源标识类 可以用来加载任意类型资源
AssetReferenceAtlasedSprite //图集资源标识类
AssetReferenceGameObject //游戏对象资源标识类
AssetReferenceSprite //精灵图片资源标识类
AssetReferenceTexture //贴图资源标识类
AssetReferenceTexture2D //2D贴图资源标识类
AssetReferenceTexture3D //3D贴图资源标识类
AssetReferenceT<> //指定类型标识类,通过泛型指定加载资源
//异步加载相关
assetReference.LoadAssetAsync<>() //通过标识类异步加载其关联的资源
AsyncOperationHandle<> //异步加载处理类
asyncOperationHandle<>.Status //异步加载状态,用于判断是否加载成功
asyncOperationHandle<>.Result //异步加载结果,用于获取加载出来的资源
asyncOperationHandle<>.Completed //异步加载完毕时会执行的事件,用于添加资源加载完毕的回调方法
assetReference.Asset //标识类异步加载得到的资源
assetReference.IsDone //标识类的资源是否加载完毕
assetReference.LoadSceneAsync() //异步加载场景
//其他
assetReference.ReleaseAsset() //卸载资源
assetReference.InstantiateAsync() //加载出来资源后就直接实例化

资源准备

image

Addressables中的资源标识类

  1. 我们可以根据自己的需求选择合适的标识类进行资源加载
  2. 资源加载和场景加载都是通过异步进行加载
  3. 需要注意异步加载资源使用时必须保证资源已经被加载成功了,否则会报错

通过不同类型标识类对象的申明 我们可以在Inspector窗口中筛选关联的资源对象

命名空间:UnityEngine.AddressableAssets

1
2
3
4
5
6
7
8
AssetReference                //通用资源标识类 可以用来加载任意类型资源
AssetReferenceAtlasedSprite //图集资源标识类
AssetReferenceGameObject //游戏对象资源标识类
AssetReferenceSprite //精灵图片资源标识类
AssetReferenceTexture //贴图资源标识类
AssetReferenceTexture2D
AssetReferenceTexture3D
AssetReferenceT<> //指定类型标识类

效果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using UnityEngine;
using UnityEngine.AddressableAssets;

public class Lesson3 : MonoBehaviour
{
public AssetReference assetReference; //通用资源标识类
public AssetReferenceAtlasedSprite asReference; //图集资源标识类
public AssetReferenceGameObject gameobjectReference; //游戏对象资源标识类
public AssetReferenceSprite spriteReference; //精灵图片资源标识类
public AssetReferenceTexture textureReference; //贴图资源标识类

public AssetReferenceT<AudioClip> audioReference; //加载音效
public AssetReferenceT<RuntimeAnimatorController> controller; //加载动画控制器
public AssetReferenceT<TextAsset> textReference; //加载文本

public AssetReferenceT<Material> materialRed; //加载材质
}

image

其中AssetReference​可以选择各种类型的资源

image

而不同类型的 AssetReference​ 只能选择特定类型的资源(以 AssetReferenceGameObject​ 为例)

image

加载资源

注意:所有Addressables​加载相关都使用异步加载

需要引用命名空间:UnityEngine.ResourceManagement.AsyncOperations

通过异步加载返回值 AsyncOperationHandle<T>​,对完成进行事件监听
其中,监听方法要求有一个AsyncOperationHandle<T>​参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
using UnityEngine.ResourceManagement.AsyncOperations;

public class Lesson3 : MonoBehaviour
{
public AssetReference assetReference; //通用资源标识类

void Start()
{
AsyncOperationHandle<GameObject> handle = assetReference.LoadAssetAsync<GameObject>();
handle.Completed += TestFun;
}

private void TestFun(AsyncOperationHandle<GameObject> handle)
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(handle.Result);
}
}
}

加载成功后使用

  1. 通过事件函数传入的参数判断加载是否成功 并且创建
  2. 通过资源标识类对象判断 并且创建
1
2
3
4
5
6
7
private void TestFun(AsyncOperationHandle<GameObject> handle)
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(handle.Result);
}
}

同样可以直接使用匿名函数来获取加载出来的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public AssetReferenceGameObject gameobjectReference;            //游戏对象资源标识类

void Start()
{
AsyncOperationHandle<GameObject> handle = assetReference.LoadAssetAsync<GameObject>();
handle.Completed += TestFun;

gameobjectReference.LoadAssetAsync<GameObject>().Completed += (handle) =>
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(handle.Result);
}
};
}

通过标识类来获取加载出来的资源

我们同样可以直接通过标识类来获取加载出来的对象,但是不推荐

通过assetReference.IsDone​来判断是否加载完毕,但不能判断加载是否失败
获取资源通过assetReference.assets​来获取资源,并且获取到的资源需要as​转换为对应的类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public AssetReference assetReference;                           //通用资源标识类

void Start()
{
AsyncOperationHandle<GameObject> handle = assetReference.LoadAssetAsync<GameObject>();
handle.Completed += TestFun;
}

private void TestFun(AsyncOperationHandle<GameObject> handle)
{
if (assetReference.IsDone)
{
Instantiate(assetReference.Asset);
}
}

加载场景

可寻址资源可用于加载场景,但需要使用另外一个API,而场景也没有对应的标识类去引用,因此直接使用通用标识类AssetReference​即可
如果有加载完毕的回调函数,直接像加载资源那样添加回调函数即可

1
2
3
4
5
6
7
8
9
10
public AssetReference sceneReference;                           //加载场景

void Start()
{
sceneReference.LoadSceneAsync().Completed += (handle) =>
{
//初始化场景相关
print("场景加载结束");
};
}

释放资源

释放资源相关API assetReference.ReleaseAsset()​,注意,请务必在资源加载完毕后才卸载资源

  1. 释放资源方法后,资源标识类中的资源会置空,但是AsyncOperationHandle​类中的对象不为空

    因此要注意,在将AsyncOperationHandle​作为成员变量存储起来后,想要彻底卸载资源,必须要将返回的AsyncOperationHandle​引用给置空!

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public AssetReferenceGameObject gameobjectReference;            //游戏对象资源标识类
    public AssetReferenceT<Material> materialRed; //加载材质

    void Start()
    {
    gameobjectReference.LoadAssetAsync<GameObject>().Completed += (handle) =>
    {
    if (handle.Status == AsyncOperationStatus.Succeeded)
    {
    GameObject cube = Instantiate(handle.Result);
    assetReference.ReleaseAsset();
    materialRed.LoadAssetAsync<Material>().Completed += (materialhandle) =>
    {
    cube.GetComponent<MeshRenderer>().material = materialhandle.Result;
    //这会导致游戏对象使用的材质丢失!!!
    materialRed.ReleaseAsset();

    print(materialRed.Asset);
    print(materialhandle.Result);
    };
    }
    };
    }

    输出结果:​image

  2. 释放资源不会影响场景中被实例化出来的对象,但如果卸载GameObject使用的资源(例如材质),就会出现丢失问题!

    上述问题会在寻址资源的Play Mode Script设置为第三种也就是真实使用AB包打包的情况下出现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public AssetReferenceGameObject gameobjectReference;            //游戏对象资源标识类
public AssetReferenceT<Material> materialRed; //加载材质

void Start()
{
gameobjectReference.LoadAssetAsync<GameObject>().Completed += (handle) =>
{
if (handle.Status == AsyncOperationStatus.Succeeded)
{
GameObject cube = Instantiate(handle.Result);
assetReference.ReleaseAsset();
materialRed.LoadAssetAsync<Material>().Completed += (materialhandle) =>
{
cube.GetComponent<MeshRenderer>().material = materialhandle.Result;
//这会导致游戏对象使用的材质丢失!!!
materialRed.ReleaseAsset();
};
}
};
}

显示效果:

image

加载出来的预设体不受卸载影响,但是依附在其之上的材质因为卸载而丢失了!

因为加载出来的预设体本质是加载了一个预设体配置文件,还需要根据该配置文件实例化游戏对象
因此卸载预设体也只是卸载了一个配置文件,而根据该文件实例化的游戏对象是不被影响的

直接实例化对象

适用于 想要实例化的 对象 才会直接使用该方法 一般都是GameObject​预设体!

该方法实例化对象时,可以同时设置这个实例化出来的对象的位置、角度,以及父子关系

1
2
3
4
5
6
public AssetReferenceGameObject gameobjectReference;            //游戏对象资源标识类

void Start()
{
gameobjectReference.InstantiateAsync(Vector3.one, Quaternion.identity);
}

自定义标识类

自定义类 继承AssetReferenceT<>​类 即可自定义一个指定类型的标识类
该功能主要用于Unity2020.1之前,因为之前的版本不能直接使用AssetReferenceT<>​泛型字段
或者说,旧版的AssetReferenceT<>​类字段是无法显示在Inspector窗口上的,因此也不能直接引用要加载的资源

要注意,自定义的标识类必须包括一个构造函数来调用父类的有参构造函数

1
2
3
4
public class AssetReferenceAudio : AssetReferenceT<AudioClip>
{
public AssetReferenceAudio(string guid) : base(guid) { }
}