BundleLoader.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import { assetManager, JsonAsset, Asset, SpriteFrame } from 'cc';
  2. /**
  3. * Bundle资源加载器
  4. * 统一管理Asset Bundle的加载和资源获取
  5. */
  6. export class BundleLoader {
  7. private static instance: BundleLoader = null;
  8. private loadedBundles: Map<string, any> = new Map();
  9. private loadingPromises: Map<string, Promise<any>> = new Map();
  10. public static getInstance(): BundleLoader {
  11. if (!BundleLoader.instance) {
  12. BundleLoader.instance = new BundleLoader();
  13. }
  14. return BundleLoader.instance;
  15. }
  16. /**
  17. * 加载Bundle
  18. * @param bundleName Bundle名称
  19. * @returns Promise<Bundle>
  20. */
  21. public async loadBundle(bundleName: string): Promise<any> {
  22. // 如果已经加载过,直接返回
  23. if (this.loadedBundles.has(bundleName)) {
  24. return this.loadedBundles.get(bundleName);
  25. }
  26. // 如果正在加载,返回加载Promise
  27. if (this.loadingPromises.has(bundleName)) {
  28. return this.loadingPromises.get(bundleName);
  29. }
  30. // 开始加载Bundle
  31. const loadingPromise = new Promise<any>((resolve, reject) => {
  32. console.log(`[BundleLoader] 开始加载Bundle: ${bundleName}`);
  33. assetManager.loadBundle(bundleName, (err, bundle) => {
  34. if (err) {
  35. console.error(`[BundleLoader] 加载Bundle失败: ${bundleName}`, err);
  36. this.loadingPromises.delete(bundleName);
  37. reject(err);
  38. return;
  39. }
  40. console.log(`[BundleLoader] Bundle加载成功: ${bundleName}`);
  41. this.loadedBundles.set(bundleName, bundle);
  42. this.loadingPromises.delete(bundleName);
  43. resolve(bundle);
  44. });
  45. });
  46. this.loadingPromises.set(bundleName, loadingPromise);
  47. return loadingPromise;
  48. }
  49. /**
  50. * 从Bundle中加载资源
  51. * @param bundleName Bundle名称
  52. * @param resourcePath 资源路径(相对于Bundle根目录)
  53. * @param assetType 资源类型
  54. * @returns Promise<Asset>
  55. */
  56. public async loadAssetFromBundle<T extends Asset>(bundleName: string, resourcePath: string, assetType?: typeof Asset): Promise<T> {
  57. try {
  58. // 先确保Bundle已加载
  59. const bundle = await this.loadBundle(bundleName);
  60. return new Promise<T>((resolve, reject) => {
  61. console.log(`[BundleLoader] 从Bundle ${bundleName} 加载资源: ${resourcePath}`);
  62. if (assetType) {
  63. bundle.load(resourcePath, assetType, (err: Error, asset: T) => {
  64. if (err) {
  65. console.error(`[BundleLoader] 从Bundle ${bundleName} 加载资源失败: ${resourcePath}`, err);
  66. reject(err);
  67. return;
  68. }
  69. console.log(`[BundleLoader] 资源加载成功: ${bundleName}/${resourcePath}`);
  70. resolve(asset);
  71. });
  72. } else {
  73. bundle.load(resourcePath, (err: Error, asset: T) => {
  74. if (err) {
  75. console.error(`[BundleLoader] 从Bundle ${bundleName} 加载资源失败: ${resourcePath}`, err);
  76. reject(err);
  77. return;
  78. }
  79. console.log(`[BundleLoader] 资源加载成功: ${bundleName}/${resourcePath}`);
  80. resolve(asset);
  81. });
  82. }
  83. });
  84. } catch (error) {
  85. console.error(`[BundleLoader] 加载资源时发生错误: ${bundleName}/${resourcePath}`, error);
  86. throw error;
  87. }
  88. }
  89. /**
  90. * 从data Bundle加载JSON资源的便捷方法
  91. * @param resourcePath 资源路径(相对于data Bundle根目录)
  92. * @returns Promise<JsonAsset>
  93. */
  94. public async loadDataJson(resourcePath: string): Promise<JsonAsset> {
  95. return this.loadAssetFromBundle<JsonAsset>('data', resourcePath, JsonAsset);
  96. }
  97. /**
  98. * 从images Bundle加载图片资源的便捷方法
  99. * @param resourcePath 资源路径(相对于images Bundle根目录)
  100. * @returns Promise<Asset>
  101. */
  102. public async loadImage(resourcePath: string): Promise<Asset> {
  103. return this.loadAssetFromBundle('images', resourcePath);
  104. }
  105. /**
  106. * 从images Bundle加载SpriteFrame资源的便捷方法
  107. * @param resourcePath 资源路径(相对于images Bundle根目录)
  108. * @returns Promise<SpriteFrame>
  109. */
  110. public async loadSpriteFrame(resourcePath: string): Promise<SpriteFrame> {
  111. return this.loadAssetFromBundle<SpriteFrame>('images', resourcePath, SpriteFrame);
  112. }
  113. /**
  114. * 从Animation Bundle加载动画资源的便捷方法
  115. * @param resourcePath 资源路径(相对于Animation Bundle根目录)
  116. * @returns Promise<Asset>
  117. */
  118. public async loadAnimation(resourcePath: string): Promise<Asset> {
  119. return this.loadAssetFromBundle('Animation', resourcePath);
  120. }
  121. /**
  122. * 检查Bundle是否已加载
  123. * @param bundleName Bundle名称
  124. * @returns boolean
  125. */
  126. public isBundleLoaded(bundleName: string): boolean {
  127. return this.loadedBundles.has(bundleName);
  128. }
  129. /**
  130. * 获取已加载的Bundle
  131. * @param bundleName Bundle名称
  132. * @returns Bundle | null
  133. */
  134. public getLoadedBundle(bundleName: string): any {
  135. return this.loadedBundles.get(bundleName) || null;
  136. }
  137. /**
  138. * 释放Bundle资源
  139. * @param bundleName Bundle名称
  140. */
  141. public releaseBundle(bundleName: string): void {
  142. const bundle = this.loadedBundles.get(bundleName);
  143. if (bundle) {
  144. bundle.releaseAll();
  145. this.loadedBundles.delete(bundleName);
  146. console.log(`[BundleLoader] Bundle已释放: ${bundleName}`);
  147. }
  148. }
  149. /**
  150. * 释放所有Bundle资源
  151. */
  152. public releaseAllBundles(): void {
  153. for (const [bundleName, bundle] of this.loadedBundles) {
  154. bundle.releaseAll();
  155. }
  156. this.loadedBundles.clear();
  157. console.log('[BundleLoader] 所有Bundle已释放');
  158. }
  159. }