357 lines
8.5 KiB
Markdown
357 lines
8.5 KiB
Markdown
# 资源管理模块 (Framework/ResMgr)
|
|
|
|
## 📋 模块概述
|
|
统一的资源加载管理器,封装 Cocos Creator 的资源加载 API,支持从 bundle 中按路径加载资源,提供资源缓存和释放机制。
|
|
|
|
## 🎯 核心特性
|
|
- ✅ 单例模式,全局统一管理
|
|
- ✅ 资源缓存机制
|
|
- ✅ Bundle 管理
|
|
- ✅ 支持单个资源加载
|
|
- ✅ 支持资源预加载
|
|
- ✅ 支持目录批量加载
|
|
- ✅ 资源释放管理
|
|
- ✅ 完整的日志输出
|
|
|
|
## 🗂️ 文件结构
|
|
|
|
```
|
|
Framework/ResMgr/
|
|
├── ResMgr.ts # 资源管理器核心
|
|
├── ResConfig.ts # 资源配置
|
|
└── ResMgrExample.ts # 使用示例
|
|
```
|
|
|
|
## 📘 核心类详解
|
|
|
|
### ResMgr - 资源管理器
|
|
|
|
**职责**: 管理资源加载、缓存和释放
|
|
|
|
```typescript
|
|
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 - 资源配置
|
|
|
|
**配置接口**:
|
|
|
|
```typescript
|
|
// 资源加载配置
|
|
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. 加载单个资源
|
|
|
|
```typescript
|
|
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. 预加载资源
|
|
|
|
```typescript
|
|
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. 加载目录
|
|
|
|
```typescript
|
|
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. 释放资源
|
|
|
|
```typescript
|
|
import { ResMgr } from './Framework/ResMgr/ResMgr';
|
|
|
|
// 释放单个资源
|
|
ResMgr.getInstance().release('resources', 'prefabs/Player');
|
|
|
|
// 释放目录资源
|
|
ResMgr.getInstance().releaseDir('resources', 'textures/ui');
|
|
|
|
// 释放所有资源(场景切换时)
|
|
ResMgr.getInstance().releaseAll();
|
|
```
|
|
|
|
### 5. 游戏场景资源管理
|
|
|
|
```typescript
|
|
// 场景资源管理器
|
|
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. **缓存机制**: 相同路径的资源会被缓存,重复加载返回缓存实例
|
|
|
|
## 🔍 调试技巧
|
|
|
|
### 查看缓存大小
|
|
|
|
```typescript
|
|
const cacheSize = ResMgr.getInstance().getCacheSize();
|
|
console.log(`当前缓存资源数量: ${cacheSize}`);
|
|
```
|
|
|
|
### 日志输出
|
|
|
|
```typescript
|
|
// ResMgr 内部包含详细日志:
|
|
// [ResMgr] 加载资源: bundleName/path
|
|
// [ResMgr] 从缓存加载: bundleName/path
|
|
// [ResMgr] 释放资源: bundleName/path
|
|
// [ResMgr] 释放目录: bundleName/dir
|
|
// [ResMgr] 释放所有资源
|
|
```
|
|
|
|
### 常见问题
|
|
|
|
**问题1**: 资源加载失败
|
|
```typescript
|
|
// 检查: bundle 是否存在、路径是否正确、类型是否匹配
|
|
try {
|
|
const prefab = await ResMgr.getInstance().load('resources', 'prefabs/Player', Prefab);
|
|
} catch (error) {
|
|
console.error('资源加载失败:', error);
|
|
}
|
|
```
|
|
|
|
**问题2**: 内存占用过高
|
|
```typescript
|
|
// 解决: 及时释放不用的资源
|
|
ResMgr.getInstance().releaseAll();
|
|
```
|
|
|
|
## 💡 最佳实践
|
|
|
|
1. **场景切换时释放**: 切换场景时调用 `releaseAll()` 清理资源
|
|
2. **按需加载**: 不要一次性加载所有资源,按需加载
|
|
3. **预加载优化**: 对大资源使用 `preload()` 在空闲时预加载
|
|
4. **目录管理**: 合理组织资源目录结构,方便批量加载和释放
|
|
5. **资源复用**: 相同资源重复使用时,利用缓存机制避免重复加载
|
|
6. **错误处理**: 资源加载使用 try-catch 处理异常情况
|
|
|
|
## 📚 常用资源类型
|
|
|
|
| 资源类型 | Cocos 类型 | 用途 |
|
|
|---------|----------|------|
|
|
| 预制体 | Prefab | 场景节点、UI 等 |
|
|
| 图片 | SpriteFrame | 精灵图、UI图标 |
|
|
| 音频 | AudioClip | 音效、背景音乐 |
|
|
| 场景 | SceneAsset | 游戏场景 |
|
|
| 字体 | Font | 文本渲染 |
|
|
| 图集 | SpriteAtlas | 批量图片资源 |
|
|
| 动画 | AnimationClip | 动画数据 |
|
|
|
|
## 🎯 应用场景
|
|
|
|
- ✅ 场景资源加载(角色、道具、环境等)
|
|
- ✅ UI 资源加载(界面预制体、图标等)
|
|
- ✅ 音频资源加载(背景音乐、音效等)
|
|
- ✅ 关卡资源动态加载
|
|
- ✅ 资源热更新
|
|
- ✅ 分包加载
|