feat: add cocos-service configuration file feat: add device configuration file feat: add engine configuration file feat: add information configuration file feat: add program configuration file feat: add project configuration file feat: add TypeScript configuration file
281 lines
10 KiB
TypeScript
281 lines
10 KiB
TypeScript
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<Node[]> 返回所有创建的节点数组
|
||
*/
|
||
loadPrefabByFrame(prefabName: string, perFrameNum: number, totalNum: number, usePool: boolean = true, callBack?: (node: Node, index: number) => void): Promise<Node[]> {
|
||
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();
|
||
}
|
||
} |