You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

移动端Idle游戏启动时异步加载资源的最优管理方案

解决方案

方案1:使用Addressables.CombineAsync合并加载操作

Addressables原生提供了CombineAsync方法,可将多个异步加载操作的句柄合并为一个,等待合并操作完成时,就代表所有子加载任务都已结束。这种方式既能保持资源并行加载的效率,又能统一监听所有加载完成的时机。

代码示例:

IEnumerator LoadAllAssetsThenSavedGame()
{
    // 同时启动三个并行加载任务,获取各自的操作句柄
    var inventoryOp = Addressables.LoadAssetsAsync<InventorySO>("InventoryLabel", null);
    var characterOp = Addressables.LoadAssetsAsync<CharacterSO>("CharacterLabel", null);
    var soundOp = Addressables.LoadAssetsAsync<SoundSO>("SoundLabel", null);

    // 合并所有加载操作
    var combinedOp = Addressables.CombineAsync(inventoryOp, characterOp, soundOp);
    yield return combinedOp;

    if (combinedOp.Status == AsyncOperationStatus.Succeeded)
    {
        // 分别提取每个加载任务的结果
        _inventoryResults = inventoryOp.Result;
        _characterResults = characterOp.Result;
        _soundResults = soundOp.Result;

        // 所有资源加载完成,执行存档加载流程
        yield return StartCoroutine(LoadSavedGame());
    }
    else
    {
        Debug.LogError("部分资源加载失败,请检查资源标签或Addressables配置");
    }
}

调用时只需启动这个合并协程:StartCoroutine(LoadAllAssetsThenSavedGame());

方案2:协程中手动跟踪所有加载操作状态

如果不想依赖CombineAsync,可以手动收集所有加载句柄,在一个协程中等待所有操作完成。这里的等待不会影响并行加载,因为所有任务已经同时启动,只是逐个确认完成状态。

代码示例:

IEnumerator LoadAllAssetsThenSavedGame()
{
    List<AsyncOperationHandle> allLoadHandles = new List<AsyncOperationHandle>();

    // 启动并行加载并收集句柄,同时用子协程存储加载结果
    var inventoryOp = Addressables.LoadAssetsAsync<InventorySO>("InventoryLabel", null);
    allLoadHandles.Add(inventoryOp);
    StartCoroutine(StoreLoadedResult(inventoryOp, ref _inventoryResults));

    var characterOp = Addressables.LoadAssetsAsync<CharacterSO>("CharacterLabel", null);
    allLoadHandles.Add(characterOp);
    StartCoroutine(StoreLoadedResult(characterOp, ref _characterResults));

    var soundOp = Addressables.LoadAssetsAsync<SoundSO>("SoundLabel", null);
    allLoadHandles.Add(soundOp);
    StartCoroutine(StoreLoadedResult(soundOp, ref _soundResults));

    // 等待所有加载操作完成
    foreach (var handle in allLoadHandles)
    {
        yield return handle;
    }

    // 所有资源就绪,执行存档加载
    yield return StartCoroutine(LoadSavedGame());
}

// 通用的结果存储协程
IEnumerator StoreLoadedResult<T>(AsyncOperationHandle<IList<T>> loadOp, ref IList<T> targetResult)
{
    yield return loadOp;
    if (loadOp.Status == AsyncOperationStatus.Succeeded)
    {
        targetResult = loadOp.Result;
    }
}

方案3:结合C# Task.WhenAll(Unity 2020+适用)

Unity 2020及以上版本支持将AsyncOperationHandle转换为Task,可利用Task.WhenAll批量等待所有任务完成,之后切回主线程执行Unity相关操作。

代码示例:

async void LoadAllAssetsThenSavedGame()
{
    // 启动并行加载并转为Task
    var inventoryTask = Addressables.LoadAssetsAsync<InventorySO>("InventoryLabel", null).Task;
    var characterTask = Addressables.LoadAssetsAsync<CharacterSO>("CharacterLabel", null).Task;
    var soundTask = Addressables.LoadAssetsAsync<SoundSO>("SoundLabel", null).Task;

    // 等待所有Task完成
    await Task.WhenAll(inventoryTask, characterTask, soundTask);

    // 提取结果(注意需确保在主线程操作Unity API)
    _inventoryResults = inventoryTask.Result;
    _characterResults = characterTask.Result;
    _soundResults = soundTask.Result;

    // 切回主线程执行存档加载
    UnityMainThreadDispatcher.Instance.Enqueue(() =>
    {
        StartCoroutine(LoadSavedGame());
    });
}

注:如果项目没有现成的主线程调度器,可自行实现一个简单版本(比如用一个MonoBehaviour维护队列,在Update中执行队列任务),避免在后台线程调用Unity API导致异常。

通用注意事项

  • 加载完成后(或场景卸载时)记得释放Addressables资源句柄:Addressables.Release(handle);,避免内存泄漏。
  • 需添加加载失败的容错逻辑,比如部分资源加载出错时,决定是否重试或终止存档加载流程。

内容的提问来源于stack exchange,提问作者Dror

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 21:10:28