10-06-YooAsset实战-Unity资源加载与使用

发布时间:2026/7/27 9:39:59

10-06-YooAsset实战-Unity资源加载与使用 实战-资源加载与使用篇章10-实战篇-从零搭建状态已完成阅读时间约 25 分钟一、引言1.1 本章在系列中的定位资源加载是 YooAsset 在运行时最常用的 API。本章系统讲解 YooAsset 的各种加载方式同步/异步加载 Prefab、Texture、Audio 等加载场景实例化与销毁加载完成回调资源释放与回收1.2 本章要解决的核心问题如何加载各种类型的资源同步和异步加载如何选择如何正确管理引用计数加载失败的降级策略1.3 阅读前置要求完成 10-01 到 10-05了解 C# async/await了解 Unity 协程二、基础加载 API2.1 同步加载using YooAsset; public class SyncLoader { public T LoadSyncT(string location) where T : Object { var op YooAssets.LoadAssetSyncT(location); return op.Result; } public Sprite LoadSprite(string location) { return LoadSyncSprite(location); } public GameObject LoadPrefab(string location) { return LoadSyncGameObject(location); } public AudioClip LoadAudio(string location) { return LoadSyncAudioClip(location); } }同步加载的适用场景启动时必须的资源Loading 界面的资源调试时快速验证注意事项会卡主线程不支持进度回调失败时无法取消2.2 异步加载public class AsyncLoader { public async TaskT LoadAsyncT(string location) where T : Object { var op YooAssets.LoadAssetAsyncT(location); await op.Task; if (op.Status ! EOperationStatus.Succeed) { Debug.LogError($加载失败: {location}, 错误: {op.Error}); return null; } return op.Result; } public async TaskSprite LoadSpriteAsync(string location) { return await LoadAsyncSprite(location); } }2.3 加载配置选项public class LoadOptions { /// summary /// 加载优先级 /// /summary public uint Priority 0; /// summary /// 是否缓存 /// /summary public bool IsCache true; /// summary /// 加载失败时是否重试 /// /summary public bool RetryOnError true; /// summary /// 加载超时秒 /// /summary public int Timeout 30; }使用var op YooAssets.LoadAssetAsyncSprite( ui_icon_home, priority: 100, // 其他选项 );2.4 加载回调public class CallbackLoader { public void LoadWithCallbackT(string location, ActionT onSuccess, Actionstring onError) where T : Object { var op YooAssets.LoadAssetAsyncT(location); op.Completed handle { if (handle.Status EOperationStatus.Succeed) onSuccess?.Invoke(handle.Result as T); else onError?.Invoke(handle.Error); }; } }三、加载各种资源类型3.1 Prefab 加载与实例化public class PrefabLoader { public async TaskGameObject InstantiateAsync(string location, Transform parent null) { // 1. 加载 Prefab var op YooAssets.LoadAssetAsyncGameObject(location); await op.Task; if (op.Status ! EOperationStatus.Succeed) return null; // 2. 实例化 var go Object.Instantiate(op.Result, parent); return go; } public void DestroyInstance(GameObject go, string location) { if (go null) return; // 1. 销毁 GameObject Object.Destroy(go); // 2. 释放资源注意会影响其他实例 // 一般不需要立即释放 } }3.2 Sprite 加载public class SpriteLoader { public async TaskSprite LoadSpriteAsync(string location) { return await LoadAsyncInternalSprite(location); } public void SetSprite(Image image, string location) { // 同步加载用于 UI 频繁刷新的场景 var sprite YooAssets.LoadAssetSyncSprite(location); if (sprite ! null) { image.sprite sprite; } } }3.3 Texture 加载public class TextureLoader { public async TaskTexture2D LoadTextureAsync(string location) { return await LoadAsyncInternalTexture2D(location); } }3.4 Audio 加载public class AudioLoader { public async TaskAudioClip LoadAudioAsync(string location) { return await LoadAsyncInternalAudioClip(location); } }3.5 场景加载public class SceneLoader { public async Task LoadSceneAsync(string sceneName, LoadSceneMode mode LoadSceneMode.Single) { var op YooAssets.LoadSceneAsync(sceneName, mode); await op.Task; if (op.Status ! EOperationStatus.Succeed) { Debug.LogError($场景加载失败: {sceneName}, 错误: {op.Error}); } } public async Task LoadSceneAdditive(string sceneName) { await LoadSceneAsync(sceneName, LoadSceneMode.Additive); } public void UnloadScene(SceneInstance scene) { YooAssets.UnloadSceneAsync(scene); } }3.6 文本/二进制加载public class TextLoader { /// summary /// 加载文本Json、Xml、Txt /// /summary public async Taskstring LoadTextAsync(string location) { var op YooAssets.GetRawFileAsync(location); await op.Task; if (op.Status ! EOperationStatus.Succeed) return null; return System.Text.Encoding.UTF8.GetString(op.Result); } /// summary /// 加载二进制 /// /summary public async Taskbyte[] LoadBytesAsync(string location) { var op YooAssets.GetRawFileAsync(location); await op.Task; return op.Status EOperationStatus.Succeed ? op.Result : null; } }3.7 ScriptableObject 加载public class ScriptableObjectLoader { public async TaskT LoadSOAsyncT(string location) where T : ScriptableObject { return await LoadAsyncInternalT(location); } public T LoadSOSyncT(string location) where T : ScriptableObject { return YooAssets.LoadAssetSyncT(location); } }四、批量加载4.1 并行加载public class BatchLoader { public async TaskListT LoadBatchAsyncT(Liststring locations) where T : Object { // 1. 创建所有加载任务 var tasks locations.Select(loc LoadInternalAsyncT(loc)).ToList(); // 2. 等待所有完成 var results await Task.WhenAll(tasks); // 3. 过滤失败 return results.Where(r r ! null).ToList(); } async TaskT LoadInternalAsyncT(string location) where T : Object { var op YooAssets.LoadAssetAsyncT(location); await op.Task; return op.Status EOperationStatus.Succeed ? op.Result : null; } }4.2 并发控制public class ControlledBatchLoader { public async TaskListT LoadBatchAsyncT( Liststring locations, int maxConcurrent 10) where T : Object { var semaphore new SemaphoreSlim(maxConcurrent); var results new ConcurrentBagT(); var failed new ConcurrentBagstring(); var tasks locations.Select(async loc { await semaphore.WaitAsync(); try { var op YooAssets.LoadAssetAsyncT(loc); await op.Task; if (op.Status EOperationStatus.Succeed) results.Add(op.Result); else failed.Add(loc); } finally { semaphore.Release(); } }); await Task.WhenAll(tasks); if (failed.Any()) { Debug.LogWarning($加载失败: {string.Join(, , failed)}); } return results.ToList(); } }4.3 加载进度跟踪public class ProgressTracker { public async TaskListT LoadWithProgressT( Liststring locations, IProgressfloat progress, int maxConcurrent 10) where T : Object { int total locations.Count; int completed 0; var lockObj new object(); var semaphore new SemaphoreSlim(maxConcurrent); var tasks locations.Select(async loc { await semaphore.WaitAsync(); try { var op YooAssets.LoadAssetAsyncT(loc); // 进度回调 while (!op.IsDone) { await Task.Yield(); } lock (lockObj) { completed; progress.Report((float)completed / total); } } finally { semaphore.Release(); } }); await Task.WhenAll(tasks); return null; // 简化返回 } } // 使用 var progress new Progressfloat(p { progressBar.value p; progressText.text ${p * 100:F1}%; }); await loader.LoadWithProgressSprite(locations, progress);五、资源释放5.1 引用计数YooAsset 自动管理引用计数public class RefCountExample { public async Task OnSceneEnter() { // 加载资源 var op1 YooAssets.LoadAssetAsyncSprite(ui_icon_1); var op2 YooAssets.LoadAssetAsyncSprite(ui_icon_2); await Task.WhenAll(op1.Task, op2.Task); // 引用计数 1, 1 } public void OnSceneExit() { // 释放资源 // 引用计数 -1 // 计数为 0 时真正释放 } }5.2 主动释放public class ResourceReleaser { /// summary /// 释放单个加载操作 /// /summary public void Release(AsyncOperationBase op) { op.Release(); } /// summary /// 批量释放 /// /summary public void ReleaseAll(ListAsyncOperationBase ops) { foreach (var op in ops) { op.Release(); } } }5.3 自动释放public class AutoReleaser : MonoBehaviour { private readonly ListAsyncOperationBase _trackedOps new(); public async TaskT LoadAndTrackT(string location) where T : Object { var op YooAssets.LoadAssetAsyncT(location); _trackedOps.Add(op); await op.Task; return op.Status EOperationStatus.Succeed ? op.Result : null; } void OnDestroy() { // GameObject 销毁时自动释放关联资源 foreach (var op in _trackedOps) { if (op.IsValid()) op.Release(); } } }5.4 内存压力下的释放public class MemoryPressureHandler { public void OnLowMemory() { // 1. 释放缓存 YooAssets.ClearCache(); // 2. 卸载未使用资源 Resources.UnloadUnusedAssets(); // 3. 强制 GC GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); Debug.Log($[Memory] 释放后: {Profiler.GetTotalAllocatedMemoryLong() / 1024 / 1024}MB); } }六、加载失败处理6.1 失败原因失败原因说明资源不存在Address 配置错误Bundle 不存在资源未被打包网络失败CDN 不可达校验失败Hash 不匹配超时网络慢或资源大6.2 失败检测public class LoadFailureDetector { public async TaskT LoadWithDetectionT(string location) where T : Object { var op YooAssets.LoadAssetAsyncT(location); await op.Task; if (op.Status EOperationStatus.Failed) { // 上报失败 ReportFailure(location, op.Error); // 重试可选 if (ShouldRetry(op.Error)) { return await RetryLoadT(location); } // 降级 return GetDefaultResourceT(); } return op.Result; } }6.3 重试策略public class RetryLoad { public async TaskT LoadWithRetryT( string location, int maxRetry 3) where T : Object { for (int i 0; i maxRetry; i) { try { var op YooAssets.LoadAssetAsyncT(location); await op.Task; if (op.Status EOperationStatus.Succeed) return op.Result; } catch (Exception ex) { Debug.LogWarning($第 {i 1} 次加载失败: {ex.Message}); } // 指数退避 await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, i))); } return GetDefaultResourceT(); } }6.4 降级策略public class FallbackStrategy { public async TaskT LoadWithFallbackT(string location) where T : Object { // 1. 尝试主资源 var op YooAssets.LoadAssetAsyncT(location); await op.Task; if (op.Status EOperationStatus.Succeed) return op.Result; // 2. 尝试备用资源 var fallbackLoc GetFallbackLocation(location); if (fallbackLoc ! null) { var fallbackOp YooAssets.LoadAssetAsyncT(fallbackLoc); await fallbackOp.Task; if (fallbackOp.Status EOperationStatus.Succeed) return fallbackOp.Result; } // 3. 使用默认资源 return GetDefaultResourceT(); } }七、加载性能优化7.1 预加载public class Preloader { public async Task Preload(Liststring locations) { var tasks locations.Select(loc YooAssets.LoadAssetAsyncObject(loc).Task ); await Task.WhenAll(tasks); // 资源已在缓存中 } }7.2 懒加载public class LazyLoader { private readonly Dictionarystring, AsyncOperationBase _cache new(); public T GetT(string location) where T : Object { if (!_cache.ContainsKey(location)) { _cache[location] YooAssets.LoadAssetAsyncT(location); } return (_cache[location] as AssetOperation)?.Result as T; } }7.3 加载策略选择场景同步异步并发数启动资源✅❌-主城资源❌✅5-10战斗资源❌✅10-20活动资源❌✅3-5DLC 资源❌✅1-3八、调试与监控8.1 加载监控public class LoadMonitor { private readonly Dictionarystring, float _loadTimes new(); public async TaskT MonitoredLoadT(string location) where T : Object { var sw Stopwatch.StartNew(); var op YooAssets.LoadAssetAsyncT(location); await op.Task; sw.Stop(); if (op.Status EOperationStatus.Succeed) { // 记录加载时间 _loadTimes[location] sw.ElapsedMilliseconds; // 上报 if (sw.ElapsedMilliseconds 1000) { Debug.LogWarning($[SlowLoad] {location}: {sw.ElapsedMilliseconds}ms); ReportSlowLoad(location, sw.ElapsedMilliseconds); } } return op.Status EOperationStatus.Succeed ? op.Result : null; } }8.2 内存监控public class MemoryMonitor { public void PrintStatus() { long totalMemory Profiler.GetTotalAllocatedMemoryLong() / 1024 / 1024; long textureMemory Profiler.GetAllocatedMemoryForGraphicsDriver() / 1024 / 1024; Debug.Log($[Memory] Total: {totalMemory}MB, Texture: {textureMemory}MB); } }九、实战案例9.1 角色加载public class CharacterLoader : MonoBehaviour { private GameObject _currentCharacter; public async Task LoadCharacter(string characterId) { // 1. 销毁旧角色 if (_currentCharacter ! null) { Destroy(_currentCharacter); } // 2. 加载新角色 var location $characters/{characterId}; var op YooAssets.LoadAssetAsyncGameObject(location); await op.Task; if (op.Status ! EOperationStatus.Succeed) { Debug.LogError($角色加载失败: {location}); return; } // 3. 实例化 _currentCharacter Instantiate(op.Result, transform); _currentCharacter.name $Character_{characterId}; } }9.2 场景切换public class SceneTransition : MonoBehaviour { public async Task TransitionToScene(string sceneName) { // 1. 显示 Loading 界面 ShowLoadingUI(); // 2. 异步加载新场景 var op YooAssets.LoadSceneAsync(sceneName, LoadSceneMode.Single); // 3. 等待加载完成 while (!op.IsDone) { UpdateProgress(op.Progress); await Task.Yield(); } if (op.Status ! EOperationStatus.Succeed) { Debug.LogError($场景加载失败: {sceneName}); return; } // 4. 隐藏 Loading HideLoadingUI(); } }十、总结10.1 本章要点回顾基础 APILoadAssetSync、LoadAssetAsync、LoadSceneAsync批量加载并行加载、并发控制、进度跟踪资源释放引用计数、主动释放、自动释放失败处理检测、重试、降级性能优化预加载、懒加载、并发策略10.2 与前后章节的关联前章10-05 介绍了资源配置与打包本章聚焦资源加载与使用后章10-07 将介绍热更新流程实现10.3 实践建议启动用同步避免 Loading 闪烁运行时用异步避免卡顿引用计数必管避免内存泄漏失败必处理每个加载都要有 fallback性能要监控加载慢的资源要优化上一篇资源配置与打包下一篇热更新流程实现

相关新闻