import { director, Node, instantiate, Prefab, Vec3, v3, SpriteFrame, Sprite, AssetManager, resources, assetManager, AudioClip, Material, Texture2D, Label } from "cc"; import { ResModel } from "../model/ResModel"; import { weiSan } from "./weiSanTools"; import { EventManager, EventData } from "../manager/EventManager"; import { PoolManager } from "../manager/PoolManager"; /** 加载资源相关工具类 */ export class LoadTools { /** 单例模式 */ private static _instance: LoadTools = new LoadTools(); private constructor() { } public static get _ins() { return this._instance; } /** * 加载游戏场景 * @param sceneName 加载场景的名字 * @param callFunc 加载回调 */ loadScene(sceneName: string, callFunc: any, isClear = true) { if (isClear) { ResModel._ins.clearResDic(); } director.preloadScene(sceneName, () => { director.loadScene(sceneName, callFunc); }); }; /** * 加载resource 下的预制体 资源 * @param url resource 下的资源路径 * @param callBack 加载完成回调 */ loadResPrefab(url: string, callBack?: any, parent?: Node, Pos?: Vec3) { this.loadResAny(url, Prefab, (prefab: Prefab) => { let clone = instantiate(prefab); if (parent) { parent.addChild(clone) }; if (Pos) { clone.position = v3(Pos.x, Pos.y, 0) }; if (callBack != null) { callBack(clone); } }) } /** * 加载resource 下的图片资源并渲染到节点上 * @param url resource 下的资源路径 * @param callBack 加载完成回调 */ loadResSpriteFrame(url: string, sprite: Node, parent?: Node, Pos?: Vec3, callBack?: any) { resources.load(url + "/spriteFrame", SpriteFrame, function (error: any, SpriteFrame: SpriteFrame) { if (error) { weiSan.error(error); } else { sprite.getComponent(Sprite).spriteFrame = SpriteFrame; if (parent) { parent.addChild(sprite) }; if (Pos) { sprite.position = v3(Pos.x, Pos.y, 0) }; if (callBack != null) { callBack(sprite); } } }); }; /** * 加载resource 下的游戏资源 * @param url resource 下的资源路径 * @param resType 加载资源的类型 * @param callBack 加载完成回调 */ loadResAny(url: string, resType: any, callBack?: any) { resources.load(url, resType, function (error: any, res: any) { if (error) { weiSan.error(error); } else { if (callBack != null) { callBack(res); } if (resType == Prefab) { ResModel._ins.PrefabDic.set(url, res); } else if (resType == SpriteFrame) { if (!ResModel._ins.SpriteFrameDic.has(url)) { ResModel._ins.SpriteFrameDic.set(url, res); } } else if (resType == AudioClip) { if (!ResModel._ins.AudioClipDic.has(url)) { ResModel._ins.AudioClipDic.set(url, res); } } else if (resType == Material) { if (!ResModel._ins.MaterialDic.has(url)) { ResModel._ins.MaterialDic.set(url, res); } } else if (resType == Texture2D) { if (!ResModel._ins.TextureDic.has(url)) { ResModel._ins.TextureDic.set(url, res); } } else if (resType === Prefab) { if (!ResModel._ins.PrefabDic.has(url)) { ResModel._ins.PrefabDic.set(url, res); } } } }); } /** 加载bundle 场景 */ loadBundleScene(bundleName: string, sceneName: string, onFinishBack?: () => void, isInScene: boolean = true) { assetManager.loadBundle( bundleName, (err: any, bundle: AssetManager.Bundle) => { if (err) { console.log(err); } else { if (!isInScene) { return; } bundle.loadScene(sceneName, (err, scene) => { if (onFinishBack) { onFinishBack(); } director.runScene(scene); }); } } ); } /** * 分帧加载预制体节点 * @param prefabName 要加载的预制体名称 * @param perFrameNum 每帧加载的数量 * @param totalNum 总共需要加载的数量 * @param usePool 是否使用对象池,默认为true * @param callBack 对每个创建的节点进行操作的回调函数 * @returns Promise 返回所有创建的节点数组 */ loadPrefabByFrame(prefabName: string, perFrameNum: number, totalNum: number, usePool: boolean = true, callBack?: (node: Node, index: number) => void): Promise { return new Promise((resolve, reject) => { // 参数验证 if (!prefabName || prefabName.trim() === '') { const error = 'prefabName cannot be empty'; weiSan.error(error); reject(new Error(error)); return; } if (perFrameNum <= 0) { const error = 'perFrameNum must be greater than 0'; weiSan.error(error); reject(new Error(error)); return; } if (totalNum <= 0) { const error = 'totalNum must be greater than 0'; weiSan.error(error); reject(new Error(error)); return; } // 触发加载开始事件 EventManager.dispatchEvent(EventData.PREFAB_LOAD_START, { prefabName: prefabName, totalNum: totalNum, usePool: usePool }); // 创建节点的函数 const createNodeFunction = (prefab?: Prefab): Node | null => { if (usePool) { // 使用对象池创建节点 return PoolManager._ins.getNode(prefabName); } else { // 使用传统方式创建节点 if (!prefab) { weiSan.error(`Prefab is required when not using pool: ${prefabName}`); return null; } return instantiate(prefab); } }; if (usePool) { // 使用对象池时,直接开始分帧创建 this.startFrameBasedCreation(prefabName, perFrameNum, totalNum, usePool, callBack, createNodeFunction, resolve, reject); } else { // 不使用对象池时,先加载预制体资源 this.loadResAny(prefabName, Prefab, (prefab: Prefab) => { if (!prefab) { const error = `Failed to load prefab: ${prefabName}`; weiSan.error(error); reject(new Error(error)); return; } this.startFrameBasedCreation(prefabName, perFrameNum, totalNum, usePool, callBack, createNodeFunction, resolve, reject, prefab); }); } }); } /** * 开始分帧创建节点的核心逻辑 */ private startFrameBasedCreation( prefabName: string, perFrameNum: number, totalNum: number, usePool: boolean, callBack: ((node: Node, index: number) => void) | undefined, createNodeFunction: (prefab?: Prefab) => Node | null, resolve: (value: Node[]) => void, reject: (reason?: any) => void, prefab?: Prefab ) { // 开始分帧创建节点 const createdNodes: Node[] = []; let currentCount = 0; const createNodesPerFrame = () => { const remainingCount = totalNum - currentCount; const currentFrameCount = Math.min(perFrameNum, remainingCount); // 创建当前帧的节点 for (let i = 0; i < currentFrameCount; i++) { try { const node = createNodeFunction(prefab); if (!node) { const error = `Failed to create node: ${prefabName}`; weiSan.error(error); reject(new Error(error)); return; } createdNodes.push(node); // 执行回调函数 if (callBack) { try { callBack(node, currentCount); } catch (callbackError) { weiSan.warn(`Callback error for node ${currentCount}: ${callbackError}`); } } currentCount++; } catch (error) { weiSan.error(`Error creating node instance: ${error}`); reject(new Error(`Error creating node instance: ${error}`)); return; } } // 计算进度并触发进度事件 const progress = (currentCount / totalNum) * 100; EventManager.dispatchEvent(EventData.PREFAB_LOAD_PROGRESS, { prefabName: prefabName, currentNum: currentCount, totalNum: totalNum, progress: progress }); // 检查是否完成 if (currentCount >= totalNum) { // 触发完成事件 EventManager.dispatchEvent(EventData.PREFAB_LOAD_COMPLETE, { prefabName: prefabName, totalNum: totalNum, nodes: createdNodes }); weiSan.log(`Successfully loaded ${totalNum} instances of prefab: ${prefabName}`); resolve(createdNodes); } else { // 继续下一帧,使用 setTimeout 来实现分帧 setTimeout(() => { createNodesPerFrame(); }, 0); } }; // 开始第一帧的创建 createNodesPerFrame(); } }