?? Unity大型項目資源管理:低端機檢測后自動切換資源框架(大廠風格)
?? 框架目標
-
? 啟動時檢測機型性能,判定設備等級
-
? 同一資源有高配/中配/低配不同壓縮格式
-
? 根據設備等級,加載對應資源包(AB)
-
? 支持動態切換(可用來切換特效/貼圖分辨率/模型LOD)
-
? 保證:
- ?? 包體小(AB按需拆分)
- ?? 加載快(AB有版本管理)
- ?? 體驗好(資源按需降級)
?? 框架結構概覽
DeviceLevelDetector (設備檢測器)↓
ResourceVersionManager(資源版本管理)↓
AssetBundleLoader(AB加載器)↓
Resource (Texture/Model/Shader/Prefab)
?? 核心概念
模塊 | 作用 |
---|---|
DeviceLevelDetector | 啟動時檢測設備性能,判定設備等級 |
ResourceVersionManager | 根據設備等級,確定要加載的資源版本(高配/中配/低配) |
AssetBundleLoader | 按需加載正確版本的AssetBundle(帶緩存機制、異步加載) |
版本化資源命名規則 | 每份資源分高/中/低版本,按規則命名: xxx_high.ab , xxx_mid.ab , xxx_low.ab |
? 低端機檢測器(DeviceLevelDetector)
(同之前提供的)
→ 返回設備等級:Low / Mid / High / Ultra
? 資源版本管理器(ResourceVersionManager)
public class ResourceVersionManager
{public enum DeviceLevel{Low,Mid,High,Ultra}private static DeviceLevel _deviceLevel;private static Dictionary<string, string> _resourceMap = new Dictionary<string, string>();public static void Init(){_deviceLevel = DeviceLevelDetector.GetDeviceLevel();Debug.Log($"[ResourceVersionManager] Device Level: {_deviceLevel}");}// 根據資源名返回對應版本的資源路徑public static string GetResourcePath(string baseName){if (_resourceMap.TryGetValue(baseName, out var path)){return path;}string suffix = GetSuffix();string versionedName = $"{baseName}_{suffix}";_resourceMap[baseName] = versionedName;return versionedName;}private static string GetSuffix(){switch (_deviceLevel){case DeviceLevel.Low: return "low";case DeviceLevel.Mid: return "mid";case DeviceLevel.High:case DeviceLevel.Ultra: return "high";default: return "mid";}}
}
? AB加載器(AssetBundleLoader)
using System.Collections;
using UnityEngine;public class AssetBundleLoader : MonoBehaviour
{private string abBasePath = Application.streamingAssetsPath + "/AssetBundles/";public IEnumerator LoadAssetAsync<T>(string baseName, string assetName, System.Action<T> onLoaded) where T : UnityEngine.Object{string versionedName = ResourceVersionManager.GetResourcePath(baseName);string abPath = abBasePath + versionedName;AssetBundleCreateRequest abRequest = AssetBundle.LoadFromFileAsync(abPath);yield return abRequest;AssetBundle bundle = abRequest.assetBundle;if (bundle == null){Debug.LogError($"[AssetBundleLoader] Failed to load AB: {abPath}");yield break;}AssetBundleRequest assetRequest = bundle.LoadAssetAsync<T>(assetName);yield return assetRequest;if (assetRequest.asset != null){onLoaded?.Invoke(assetRequest.asset as T);}else{Debug.LogError(