来源:https://www.youtube.com/watch?v=C6i_JiRoIfk

先在Package Manager里面下载好Addressable包。Addressable整体基于Unity Asset Bundle。

在Window——Asset Management——Addressables——Group点击打开Addressable Groups窗口。点击窗口内的“Create Addressable Settings”。

Addressable Groups

我们可以在Groups窗口上右键——Create New Group。不同的Group在Build的时候会打成不同的Asset Bundle。

接下来,将需要管理的资产放进Group里面,可以直接把资产向Groups窗口上的Group拖拽,也可以勾选每个资产Inspector窗口上的“Addressable”复选框,勾选后每个资产对应的路径都会显示在后面。

我们还可以把包含整个资产的文件夹拖拽进来,这样文件夹内的所有资产都会打上Addressable标记。

一个文件夹被标记为Addressable后,再放进此文件夹的新资产都会自动设置为Addressable

Group放进资产

通过脚本使用Addressable

在Scripts文件夹下新建SpawnObjectAddressable脚本,同时在Scene中新建空对象命名为“SpawnObjectAddressable”并挂载这个脚本。

一个加载场景的示例:

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

public class SpawnObjectAddressable : MonoBehaviour
{

// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.T))
{
AsyncOperationHandle loadSceneHandle = Addressables.LoadSceneAsync("Assets/Scenes/SampleScene.unity",LoadSceneMode.Single,true,1);

loadSceneHandle.Completed += AsyncOperationHanle_Completed;
}
}

private void AsyncOperationHanle_Completed(AsyncOperationHandle asyncOperationHandle)
{
}
}

一个实例化prefab的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class SpawnObjectAddressable : MonoBehaviour
{

// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.T))
{
AsyncOperationHandle<GameObject> loadSceneHandle = Addressables.LoadAssetAsync<GameObject>("Assets/Square.prefab");

loadSceneHandle.Completed += AsyncOperationHanle_Completed;
}
}

private void AsyncOperationHanle_Completed(AsyncOperationHandle<GameObject> asyncOperationHandle)
{
if(asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(asyncOperationHandle.Result);
}
else
{
Debug.Log("Load Failed!");
}
}
}

声明为AsyncOperationHandle<GameObject>才可以提供AsyncOperationHandle.Status属性

在Addressables Group窗口中,我们可以选择简化当前资产key的名称,默认情况下是完整路径名:

简化Addressable Name

使用AssetRefference来引用资产

我们修改一下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class SpawnObjectAddressable : MonoBehaviour
{
[SerializeField] private AssetReference assetReference;
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.T))
{
squarePrefab.LoadAssetAsync<GameObject>()
.Completed += asyncOperationHandle =>
{
if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(asyncOperationHandle.Result);
}
else
{
Debug.Log("Load Failed!");
}
};

}
}
}

在此脚本的Inspector窗口中,就会出现AssetReference:

添加Reference

使用AssetLabelReference来引用资产

创建Label并标记资产

Addressable Label

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class SpawnObjectAddressable : MonoBehaviour
{
[SerializeField] private AssetReference assetReference;
[SerializeField] private AssetLabelReference assetLabelReference;
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.T))
{
assetReference.LoadAssetAsync<GameObject>()
.Completed += asyncOperationHandle =>
{
if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(asyncOperationHandle.Result);
}
else
{
Debug.Log("Load Failed!");
}
};
Addressables.LoadAssetAsync<GameObject>(assetLabelReference)
.Completed += asyncOperationHandle =>
{
if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(asyncOperationHandle.Result);
}
else
{
Debug.Log("Load Failed!");
}
};
}
}
}

使用Label引用复数资产

我们可以将复数资产所在地文件夹直接打上Label

打上Label

在代码中直接引用

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

public class SpawnObjectAddressable : MonoBehaviour
{
[SerializeField] private AssetLabelReference assetLabelReference;
// Update is called once per frame
void Update()
{
Addressables.LoadAssetAsync<Sprite>(assetLabelReference, sprite => {
Debug.Log(sprite.name);
});
}
}
}

使用特定的AssetReference类

我们使用private AssetReference assetReference来引用资产,在编辑器中无法做到资产纠错,为防止资产引用错误,我们可以使用特定的AssetReference类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class SpawnObjectAddressable : MonoBehaviour
{
[SerializeField] private AssetReference assetReference;
[SerializeField] private AssetReferenceGameObject gameObjectReference;
[SerializeField] private AssetReferenceAtlasedSprite atlasedSprite;
[SerializeField] private AssetReferenceSprite sprite;
[SerializeField] private AssetReferenceTexture texture;
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.T))
{
gameObjectReference.LoadAssetAsync<GameObject>()
.Completed += asyncOperationHandle =>
{
if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
{
Instantiate(asyncOperationHandle.Result);
}
else
{
Debug.Log("Load Failed!");
}
};

}
}
}

Specific Addressable Reference

自定义AssetReference

我们可以通过继承AssetReferenceT<>非常简单地自定义AssetReference

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

[System.Serializable]
public class AssetReferenceAudioClip : AssetReferenceT<AudioClip>
{
public AssetReferenceAudioClip(string guid) : base(guid)
{
}
}
public class SpawnObjectAddressable : MonoBehaviour
{
[SerializeField] private AssetReference assetReference;
[SerializeField] private AssetReferenceGameObject gameObjectReference;
[SerializeField] private AssetReferenceAtlasedSprite atlasedSprite;
[SerializeField] private AssetReferenceSprite sprite;
[SerializeField] private AssetReferenceTexture texture;
[SerializeField] private AssetReferenceAudioClip audioClip;
//...
}

使用InstantiateAsync API更快地实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

[System.Serializable]
public class AssetReferenceAudioClip : AssetReferenceT<AudioClip>
{
public AssetReferenceAudioClip(string guid) : base(guid)
{
}
}
public class SpawnObjectAddressable : MonoBehaviour
{
[SerializeField] private AssetReference assetReference;
[SerializeField] private AssetReferenceGameObject gameObjectReference;
[SerializeField] private AssetReferenceAtlasedSprite atlasedSprite;
[SerializeField] private AssetReferenceSprite sprite;
[SerializeField] private AssetReferenceTexture texture;
[SerializeField] private AssetReferenceAudioClip audioClip;
// Update is called once per frame
void Update()
{
if(Input.GetKeyDown(KeyCode.T))
{
gameObjectReference.InstantiateAsync();
//gameObjectReference.LoadAssetAsync<GameObject>()
// .Completed += asyncOperationHandle =>
// {
// if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)
// {
// Instantiate(asyncOperationHandle.Result);
// }
// else
// {
// Debug.Log("Load Failed!");
// }
// };

}
}

释放资产

可以使用Addressables.Release(AsyncOperationHandle handle)来释放内存。

也可以使用Addressables.ReleaseInstance配合Addressables.InstantiateAsync来释放特定对象的内存

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

public class SpawnObjectAddressable : MonoBehaviour
{
[SerializeField] private AssetReferenceGameObject gameObjectReference;
private GameObject spawnedObject;
void Update()
{
if(Input.GetKeyDown(KeyCode.T))
{
gameObjectReference.InstantiateAsync().Completed += asyncOperation => spawnedObject = asyncOperation.Result;

}
if(Input.GetKeyUp(KeyCode.U))
{
gameObjectReference.ReleaseInstance(spawnedObject);
}
}
}