资源加载管理器(C#+GodotAPI)
以Godot的API为例子,Unity可以参考
资源加载器的核心:缓存
带引用计数的多级缓存加+池化
核心原理1:用一个字典存已经加载过的资源
private static Dictionary<string, Resource> _cache = new(); public static T Load<T>(string path) where T : Resource { // 1. 先查字典 if (_cache.TryGetValue(path, out var cached)) { return cached as T; } // 2. 字典里没有,才真正加载 var resource = ResourceLoader.Load<T>(path); // 3. 存到字典里 _cache[path] = resource; return resource; }
核心原理2:引用计数
资源加载了,会有一个问题:什么时候去释放资源,通过引用计数看有多少地方在使用这个资源。
private static Dictionary<string, int> _refCounts = new(); public static T Load<T>(string path) { if (_cache.TryGetValue(path, out var cached)) { _refCounts[path]++; // 引用计数+1 return cached; } var resource = ResourceLoader.Load<T>(path); _cache[path] = resource; _refCounts[path] = 1; // 首次加载,引用计数=1 return resource; } public static void Unload(string path) { if (!_refCounts.ContainsKey(path)) return; _refCounts[path]--; // 引用计数-1 if (_refCounts[path] <= 0) { // 没人用了,可以删掉了 _cache.Remove(path); _refCounts.Remove(path); // 注意:Godot 的 Resource 会被 GC 自动回收 } }
核心原理3:场景池化
资源加载好了,还需要实例化Instantiate它,场景池就是为了解决频繁实例化的问题。
场景池的原理:用完不删,下次接着用
private static Dictionary<string, List<Node>> _pools = new(); public static Node GetFromPool(string scenePath) { // 1. 池里有现成的吗? if (_pools.TryGetValue(scenePath, out var pool) && pool.Count > 0) { var instance = pool[0]; pool.RemoveAt(0); instance.Visible = true; return instance; // 复用旧的,不创建新的 } // 2. 池空了,才创建新的 var scene = ResourceLoader.Load<PackedScene>(scenePath); return scene.Instantiate(); } public static void ReturnToPool(Node instance) { instance.Visible = false; _pools[instance.SceneFilePath].Add(instance); // 藏起来 }
还需要异步加载资源:Godot本身有提供异步加载方法,后续可以在资源管理器里对加载方法进行封装
var loader = ResourceLoader.LoadAsync<Texture2D>("res://4k_bg.png");

浙公网安备 33010602011771号