using System; using System.Collections.Generic; using System.IO; using UnityEngine; namespace TcgEngine { /// /// 动态Sprite加载器,支持从本地下载的资源中加载图片 /// public class SpriteLoader : MonoBehaviour { private static SpriteLoader instance; private Dictionary spriteCache = new Dictionary(); private Dictionary textureCache = new Dictionary(); public static SpriteLoader Instance { get { if (instance == null) { GameObject go = new GameObject("SpriteLoader"); instance = go.AddComponent(); DontDestroyOnLoad(go); } return instance; } } private void Awake() { if (instance == null) { instance = this; DontDestroyOnLoad(gameObject); } else if (instance != this) { Destroy(gameObject); } } /// /// 从本地文件加载Sprite /// /// 相对于Sprites文件夹的路径 /// 加载的Sprite,失败返回null public Sprite LoadSprite(string relativePath) { if (string.IsNullOrEmpty(relativePath)) { Debug.LogWarning("[SpriteLoader] Empty relativePath provided"); return null; } // Debug.Log($"[SpriteLoader] Loading sprite: {relativePath}"); // 检查缓存 if (spriteCache.ContainsKey(relativePath)) { // Debug.Log($"[SpriteLoader] Found in cache: {relativePath}"); return spriteCache[relativePath]; } try { // 先尝试从下载的本地资源加载 string localPath = GetLocalSpritePath(relativePath); Debug.Log($"[SpriteLoader] Checking local path: {localPath}"); if (File.Exists(localPath)) { Debug.Log($"[SpriteLoader] Local file exists, loading from: {localPath}"); Sprite sprite = LoadSpriteFromFile(localPath); if (sprite != null) { Debug.Log($"[SpriteLoader] Successfully loaded from local file: {relativePath}"); spriteCache[relativePath] = sprite; return sprite; } else { Debug.LogWarning($"[SpriteLoader] Failed to load sprite from local file: {localPath}"); } } else { Debug.LogWarning($"[SpriteLoader] Local file does not exist: {localPath}"); } // 如果本地文件不存在,尝试从Resources加载(fallback) Debug.Log($"[SpriteLoader] Trying Resources fallback for: {relativePath}"); Sprite fallbackSprite = LoadSpriteFromResources(relativePath); if (fallbackSprite != null) { Debug.Log($"[SpriteLoader] Successfully loaded from Resources: {relativePath}"); spriteCache[relativePath] = fallbackSprite; return fallbackSprite; } Debug.LogWarning($"[SpriteLoader] Failed to load sprite from both local and Resources: {relativePath}"); return null; } catch (Exception e) { Debug.LogError($"[SpriteLoader] Error loading sprite {relativePath}: {e.Message}"); return null; } } /// /// 从文件系统加载Sprite /// private Sprite LoadSpriteFromFile(string filePath) { try { // 加载纹理 Texture2D texture = LoadTextureFromFile(filePath); if (texture == null) return null; // 创建Sprite Sprite sprite = Sprite.Create( texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f) ); return sprite; } catch (Exception e) { Debug.LogError($"Error loading sprite from file {filePath}: {e.Message}"); return null; } } /// /// 从文件加载纹理 /// private Texture2D LoadTextureFromFile(string filePath) { if (textureCache.ContainsKey(filePath)) { return textureCache[filePath]; } try { byte[] fileData = File.ReadAllBytes(filePath); Texture2D texture = new Texture2D(2, 2); if (texture.LoadImage(fileData)) { textureCache[filePath] = texture; return texture; } else { Destroy(texture); return null; } } catch (Exception e) { Debug.LogError($"Error loading texture from file {filePath}: {e.Message}"); return null; } } /// /// 从Resources文件夹加载Sprite(fallback) /// private Sprite LoadSpriteFromResources(string relativePath) { try { // 移除文件扩展名 string resourcePath = Path.ChangeExtension(relativePath, null); // 尝试直接加载Sprite Sprite sprite = Resources.Load(resourcePath); if (sprite != null) return sprite; // 如果直接加载失败,尝试加载Texture2D然后转换 Texture2D texture = Resources.Load(resourcePath); if (texture != null) { return Sprite.Create( texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f) ); } return null; } catch (Exception e) { Debug.LogError($"Error loading sprite from resources {relativePath}: {e.Message}"); return null; } } /// /// 获取本地Sprite文件路径 /// private string GetLocalSpritePath(string relativePath) { if (ResourceDownloader.Get() != null) { return ResourceDownloader.Get().GetLocalSpritePath(relativePath); } // Fallback路径 string basePath = Path.Combine(Application.persistentDataPath, "Sprites"); return Path.Combine(basePath, relativePath); } /// /// 清理缓存 /// public void ClearCache() { foreach (var sprite in spriteCache.Values) { if (sprite != null) Destroy(sprite); } spriteCache.Clear(); foreach (var texture in textureCache.Values) { if (texture != null) Destroy(texture); } textureCache.Clear(); } /// /// 预加载指定目录下的所有图片 /// public void PreloadSprites(string directory) { try { string localDir = GetLocalSpritePath(directory); if (!Directory.Exists(localDir)) return; string[] files = Directory.GetFiles(localDir, "*.png", SearchOption.AllDirectories); foreach (string file in files) { string relativePath = GetRelativePath(file); LoadSprite(relativePath); } } catch (Exception e) { Debug.LogError($"Error preloading sprites from {directory}: {e.Message}"); } } /// /// 获取相对路径 /// private string GetRelativePath(string fullPath) { string spritesPath = GetLocalSpritePath(""); if (fullPath.StartsWith(spritesPath)) { return fullPath.Substring(spritesPath.Length + 1); } return fullPath; } /// /// 检查Sprite是否存在 /// public bool SpriteExists(string relativePath) { if (spriteCache.ContainsKey(relativePath)) return true; string localPath = GetLocalSpritePath(relativePath); if (File.Exists(localPath)) return true; // 检查Resources string resourcePath = Path.ChangeExtension(relativePath, null); Sprite sprite = Resources.Load(resourcePath); if (sprite != null) { Resources.UnloadAsset(sprite); return true; } Texture2D texture = Resources.Load(resourcePath); if (texture != null) { Resources.UnloadAsset(texture); return true; } return false; } private void OnDestroy() { ClearCache(); } public static SpriteLoader Get() { return Instance; } } }