mcpField
U
Unity Addressables

Unity Addressables

github.com/juliankerignard开发852 次安装32 周前更新
代码仓库

关于 Unity Addressables

面向需要异步加载、分组管理、内存管理或远程内容的开发者,介绍如何使用 Unity Addressables 管理资源。还涵盖从 Resources.Load 迁移,以及释放句柄以避免内存泄漏。

主要功能

  1. 01异步加载资源
  2. 02按组和标签组织资源
  3. 03带进度预加载资源
  4. 04管理句柄与引用计数
  5. 05通过 Addressables 加载场景
  6. 06从 Resources.Load 迁移

适用场景

  1. 01在 Unity 项目中按需加载资源
  2. 02管理可选内容或场景专属内容
  3. 03通过释放句柄避免内存泄漏
  4. 04将现有 Resources.Load 用法迁移到 Addressables

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/juliankerignard/unity-skills --skill unity-addressables

安装后在 Claude Code 中输入/unity-addressables确认已加载。

附带文件references/addressables-patterns.md

详细介绍

Unity Addressables

此技能的功能

指导如何使用 Addressables 系统进行异步资源加载、分组组织、内存管理和远程内容(CDN/DLC)管理。涵盖从 Resources.Load 迁移、带进度的预加载、引用计数,以及避免内存泄漏的释放模式。

前提条件

  • 通过 Package Manager 安装 com.unity.addressables 包

快速开始

  1. 安装包:Window > Package Manager > Unity Registry > Addressables
  2. 打开 Window > Asset Management > Addressables > Groups
  3. 将资源标记为“Addressable”(Inspector 中的复选框)
  4. 按逻辑组织分组(按功能、场景或下载内容)
  5. 使用 Addressables.LoadAssetAsync<T> 加载

决策树

Comment charger cet asset ?
|
+-- Toujours en memoire, reference directe dans l'Inspector ?
|   --> Reference directe [SerializeField] (pas besoin d'Addressables)
|
+-- Charge a la demande, connu au compile-time ?
|   --> AssetReference dans l'Inspector + LoadAssetAsync
|
+-- Charge dynamiquement par label/nom ?
|   --> Addressables.LoadAssetsAsync avec label
|
+-- Contenu telechargeable (DLC, patches) ?
|   --> Remote group + catalog update
|
+-- Migration depuis Resources.Load ?
    --> Marquer les assets comme Addressable, remplacer Resources.Load par LoadAssetAsync

分步指南

Step 1:分组组织
  • 按功能分组:Characters、Levels、UI、Audio
  • 按下载内容分组:Core(包含在构建中)、Optional(可下载)
  • 如果按场景加载,则按场景分组
  • 避免分组过大(> 50 MB):按用途拆分为子组
  • 使用标签标记跨组资源(level1、boss、tutorial)
Step 2:使用句柄异步加载
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class AssetLoader : MonoBehaviour
{
    [SerializeField] private AssetReference prefabRef;
    private AsyncOperationHandle<GameObject> handle;

    public async Awaitable<GameObject> LoadAndInstantiateAsync()
    {
        handle = Addressables.LoadAssetAsync<GameObject>(prefabRef);
        await handle.Task;

        if (handle.Status == AsyncOperationStatus.Succeeded)
            return Instantiate(handle.Result);

        Debug.LogError($"Failed to load: {prefabRef}");
        return null;
    }

    private void OnDestroy()
    {
        // CRITIQUE: toujours release le handle
        if (handle.IsValid())
            Addressables.Release(handle);
    }
}

要点:

  • 在 Inspector 中使用 AssetReference,避免使用魔法字符串
  • 使用 await handle.Task 等待加载完成
  • 使用 handle.Result 前,务必检查 handle.Status
  • 在 OnDestroy 中调用 Release,以避免泄漏
Step 3:按标签加载
public class LabelLoader : MonoBehaviour
{
    [SerializeField] private AssetLabelReference labelRef;
    private AsyncOperationHandle<IList<GameObject>> handle;

    public async Awaitable<IList<GameObject>> LoadAllAsync()
    {
        handle = Addressables.LoadAssetsAsync<GameObject>(labelRef, null);
        await handle.Task;

        if (handle.Status == AsyncOperationStatus.Succeeded)
            return handle.Result;

        Debug.LogError($"Failed to load label: {labelRef}");
        return null;
    }

    private void OnDestroy()
    {
        if (handle.IsValid())
            Addressables.Release(handle);
    }
}
Step 4:从 Resources.Load 迁移到 Addressables
// AVANT (synchrone, tout en memoire au build)
var prefab = Resources.Load<GameObject>("Enemies/Goblin");

// APRES (async, charge a la demande)
var handle = Addressables.LoadAssetAsync<GameObject>("Enemies/Goblin");
await handle.Task;
var prefab = handle.Result;
// ... utiliser prefab ...
Addressables.Release(handle);

迁移步骤:

  1. 将资源移出 Resources/ 文件夹
  2. 将每个资源标记为 Addressable(Inspector 复选框)
  3. 确认 address 与原来的 Resources/ 路径一致
  4. 将 Resources.Load<T>(path) 替换为 Addressables.LoadAssetAsync<T>(address)
  5. 不再需要资源时,添加 Release()
  6. 迁移完成后,删除 Resources/ 文件夹
Step 5:Addressables 场景
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.ResourceProviders;

public class SceneLoader : MonoBehaviour
{
    [SerializeField] private AssetReference sceneRef;
    private AsyncOperationHandle<SceneInstance> sceneHandle;

    public async Awaitable LoadSceneAsync()
    {
        sceneHandle = Addressables.LoadSceneAsync(sceneRef);
        await sceneHandle.Task;
    }

    public async Awaitable UnloadSceneAsync()
    {
        if (sceneHandle.IsValid())
        {
            await Addressables.UnloadSceneAsync(sceneHandle).Task;
        }
    }
}

严格规则

  • 始终在不再需要资源时调用 Addressables.Release(handle)
  • 始终在 Inspector 中使用 AssetReference(不要硬编码 string addresses)
  • 始终处理加载失败的情况(handle.Status)
  • 始终对通过 InstantiateAsync 创建的对象使用 Addressables.ReleaseInstance(),而不是 Destroy()
  • 绝不在新项目中使用 Resources.Load(使用 Addressables)
  • 绝不保留未释放的句柄(会导致内存泄漏)
  • 绝不在没有引用计数的情况下重复加载同一资源
  • 优先使用 AssetReferenceT<T> 对引用进行类型化(AssetReferenceGameObject、AssetReferenceSprite 等)
  • 优先使用 Inspector 中的 AssetLabelReference,而不是标签字符串

相关技能

  • /perf-audit:检测内存泄漏和未释放的资源
  • /unity-build-config:构建内容和远程目录
  • /unity-code-gen:生成加载系统和资源管理器

故障排查

问题解决方案
"InvalidKeyException"地址或标签不存在。请在 Addressables Groups window 中检查
内存泄漏忘记调用 Release()。请使用 Addressables Profiler(Event Viewer)
构建不包含资源资源不属于任何组,或该组未包含在构建中
加载缓慢组过大。请按用途拆分为多个子组
"Cannot instantiate"资源不是预制件,或加载失败(请检查 Status)
"Exception during init"Addressables 尚未初始化。请先调用 Addressables.InitializeAsync()
资源重复某个资源属于多个组。请使用 Build Report 检测
远程目录未更新启动时调用 CheckForCatalogUpdates,然后调用 UpdateCatalogs

评论

支持 Markdown