Files
2025-12-14 22:40:00 +08:00

8.5 KiB

资源管理模块 (Framework/ResMgr)

📋 模块概述

统一的资源加载管理器,封装 Cocos Creator 的资源加载 API,支持从 bundle 中按路径加载资源,提供资源缓存和释放机制。

🎯 核心特性

  • 单例模式,全局统一管理
  • 资源缓存机制
  • Bundle 管理
  • 支持单个资源加载
  • 支持资源预加载
  • 支持目录批量加载
  • 资源释放管理
  • 完整的日志输出

🗂️ 文件结构

Framework/ResMgr/
├── ResMgr.ts         # 资源管理器核心
├── ResConfig.ts      # 资源配置
└── ResMgrExample.ts  # 使用示例

📘 核心类详解

ResMgr - 资源管理器

职责: 管理资源加载、缓存和释放

class ResMgr {
    // 获取单例
    static getInstance(): ResMgr;
    
    // 加载单个资源
    load<T extends Asset>(
        bundleName: string,
        path: string,
        type: typeof Asset
    ): Promise<T>;
    
    // 预加载资源(不实例化)
    preload<T extends Asset>(
        bundleName: string,
        path: string,
        type: typeof Asset,
        onProgress?: (finished: number, total: number) => void
    ): Promise<void>;
    
    // 加载目录
    loadDir<T extends Asset>(
        bundleName: string,
        dir: string,
        type: typeof Asset
    ): Promise<T[]>;
    
    // 释放单个资源
    release(bundleName: string, path: string): void;
    
    // 释放目录资源
    releaseDir(bundleName: string, dir: string): void;
    
    // 释放所有资源
    releaseAll(): void;
    
    // 获取缓存大小
    getCacheSize(): number;
}

ResConfig - 资源配置

配置接口:

// 资源加载配置
interface ResLoadConfig {
    showProgress?: boolean;    // 是否显示加载进度
    timeout?: number;          // 加载超时时间(ms)
    retryCount?: number;       // 失败重试次数
}

// 预加载配置
interface PreloadConfig extends ResLoadConfig {
    onProgress?: (finished: number, total: number) => void;
}

// 常用资源路径
class ResPath {
    static readonly PREFAB = 'prefabs';
    static readonly TEXTURE = 'textures';
    static readonly AUDIO = 'audio';
    static readonly SCENE = 'scenes';
}

// 资源类型枚举
enum ResType {
    Prefab = 'Prefab',
    Texture = 'Texture',
    Audio = 'Audio',
    Scene = 'Scene'
}

📝 使用指南

1. 加载单个资源

import { ResMgr } from './Framework/ResMgr/ResMgr';
import { Prefab, SpriteFrame, AudioClip } from 'cc';

// 加载预制体
const prefab = await ResMgr.getInstance().load<Prefab>(
    'resources',
    'prefabs/Player',
    Prefab
);

// 加载图片
const spriteFrame = await ResMgr.getInstance().load<SpriteFrame>(
    'resources',
    'textures/icon',
    SpriteFrame
);

// 加载音频
const audioClip = await ResMgr.getInstance().load<AudioClip>(
    'resources',
    'audio/bgm',
    AudioClip
);

2. 预加载资源

import { ResMgr } from './Framework/ResMgr/ResMgr';
import { Prefab } from 'cc';

// 预加载资源(带进度回调)
await ResMgr.getInstance().preload<Prefab>(
    'resources',
    'prefabs/Enemy',
    Prefab,
    (finished, total) => {
        const progress = (finished / total * 100).toFixed(0);
        console.log(`预加载进度: ${progress}%`);
    }
);

// 预加载完成后再实际加载
const prefab = await ResMgr.getInstance().load<Prefab>(
    'resources',
    'prefabs/Enemy',
    Prefab
);

3. 加载目录

import { ResMgr } from './Framework/ResMgr/ResMgr';
import { SpriteFrame } from 'cc';

// 加载整个目录的资源
const sprites = await ResMgr.getInstance().loadDir<SpriteFrame>(
    'resources',
    'textures/ui',
    SpriteFrame
);

console.log(`加载了 ${sprites.length} 个图片资源`);

// 使用加载的资源
for (const sprite of sprites) {
    console.log(`资源名称: ${sprite.name}`);
}

4. 释放资源

import { ResMgr } from './Framework/ResMgr/ResMgr';

// 释放单个资源
ResMgr.getInstance().release('resources', 'prefabs/Player');

// 释放目录资源
ResMgr.getInstance().releaseDir('resources', 'textures/ui');

// 释放所有资源(场景切换时)
ResMgr.getInstance().releaseAll();

5. 游戏场景资源管理

// 场景资源管理器
class SceneResMgr {
    private _loadedRes: string[] = [];
    
    // 加载场景所需资源
    async loadSceneRes(): Promise<void> {
        const resMgr = ResMgr.getInstance();
        
        // 加载角色
        await resMgr.load('resources', 'prefabs/Player', Prefab);
        this._loadedRes.push('prefabs/Player');
        
        // 加载敌人
        await resMgr.load('resources', 'prefabs/Enemy', Prefab);
        this._loadedRes.push('prefabs/Enemy');
        
        // 加载UI
        const uiSprites = await resMgr.loadDir(
            'resources',
            'textures/ui',
            SpriteFrame
        );
        this._loadedRes.push('textures/ui');
        
        console.log(`场景资源加载完成,共 ${this._loadedRes.length} 项`);
    }
    
    // 释放场景资源
    releaseSceneRes(): void {
        const resMgr = ResMgr.getInstance();
        
        for (const resPath of this._loadedRes) {
            if (resPath.endsWith('/')) {
                resMgr.releaseDir('resources', resPath);
            } else {
                resMgr.release('resources', resPath);
            }
        }
        
        this._loadedRes = [];
        console.log('场景资源已释放');
    }
}

🔄 资源加载流程

ResMgr.load(bundleName, path, type)
    ↓
1. 检查缓存
    ↓
2. 如果已缓存,直接返回
    ↓
3. 通过 assetManager 加载 bundle
    ↓
4. 从 bundle 加载资源
    ↓
5. 存入缓存
    ↓
6. 返回资源实例

📊 资源生命周期

[请求加载资源]
    ↓
load() / preload() / loadDir()
    ↓
资源加载到内存
    ↓
缓存资源引用
    ↓
[使用资源]
    ↓
release() / releaseDir() / releaseAll()
    ↓
资源从内存释放

⚠️ 注意事项

  1. Bundle 必须存在: 确保 bundleName 对应的 bundle 已在 Cocos 中配置
  2. 路径不含扩展名: 资源路径不需要包含文件扩展名
  3. 类型要匹配: 加载时的 type 参数必须与实际资源类型匹配
  4. 及时释放资源: 不再使用的资源应及时释放,避免内存泄漏
  5. 目录加载限制: loadDir 只加载指定目录下的资源,不递归子目录
  6. 缓存机制: 相同路径的资源会被缓存,重复加载返回缓存实例

🔍 调试技巧

查看缓存大小

const cacheSize = ResMgr.getInstance().getCacheSize();
console.log(`当前缓存资源数量: ${cacheSize}`);

日志输出

// ResMgr 内部包含详细日志:
// [ResMgr] 加载资源: bundleName/path
// [ResMgr] 从缓存加载: bundleName/path
// [ResMgr] 释放资源: bundleName/path
// [ResMgr] 释放目录: bundleName/dir
// [ResMgr] 释放所有资源

常见问题

问题1: 资源加载失败

// 检查: bundle 是否存在、路径是否正确、类型是否匹配
try {
    const prefab = await ResMgr.getInstance().load('resources', 'prefabs/Player', Prefab);
} catch (error) {
    console.error('资源加载失败:', error);
}

问题2: 内存占用过高

// 解决: 及时释放不用的资源
ResMgr.getInstance().releaseAll();

💡 最佳实践

  1. 场景切换时释放: 切换场景时调用 releaseAll() 清理资源
  2. 按需加载: 不要一次性加载所有资源,按需加载
  3. 预加载优化: 对大资源使用 preload() 在空闲时预加载
  4. 目录管理: 合理组织资源目录结构,方便批量加载和释放
  5. 资源复用: 相同资源重复使用时,利用缓存机制避免重复加载
  6. 错误处理: 资源加载使用 try-catch 处理异常情况

📚 常用资源类型

资源类型 Cocos 类型 用途
预制体 Prefab 场景节点、UI 等
图片 SpriteFrame 精灵图、UI图标
音频 AudioClip 音效、背景音乐
场景 SceneAsset 游戏场景
字体 Font 文本渲染
图集 SpriteAtlas 批量图片资源
动画 AnimationClip 动画数据

🎯 应用场景

  • 场景资源加载(角色、道具、环境等)
  • UI 资源加载(界面预制体、图标等)
  • 音频资源加载(背景音乐、音效等)
  • 关卡资源动态加载
  • 资源热更新
  • 分包加载