mirror of
https://gitee.com/dgflash/oops-plugin-framework.git
synced 2026-05-09 03:46:04 +08:00
2. 存储模块性能提升,添加LRU缓存、批量操作支持,优化内存使用 3. 多语言模块性能与内存管理优化,组件查询性能提升 4. 时间模块类型安全与性能优化,使用泛型替代any,对象池机制减少内存分配 5. 事件系统修复双重注册、重复注册等严重问题,实现EventData对象池减少GC压力 6. RandomManager修复4个逻辑BUG,包括边界问题和越界问题 7. 音频模块内存与性能优化,避免重复加载,优化数据结构,添加完整清理机制 8. CCView与CCViewVM合并,支持按需启用MVVM 9. Collection模块优化,AsyncQueue添加队列容量限制,Collection查询性能提升 10. ECS系统全面优化,对象池复用减少内存分配,循环性能提升 11. 优化MVVM组件性能
271 lines
8.2 KiB
TypeScript
271 lines
8.2 KiB
TypeScript
/*
|
|
* @Author: dgflash
|
|
* @Date: 2021-10-12 14:00:43
|
|
* @LastEditors: dgflash
|
|
* @LastEditTime: 2023-03-06 14:40:34
|
|
*/
|
|
import type { Node, Vec3 } from 'cc';
|
|
import { Animation, NodePool, ParticleSystem, Prefab, sp } from 'cc';
|
|
import { message } from '../../core/common/event/MessageManager';
|
|
import { resLoader } from '../../core/common/loader/ResLoader';
|
|
import { ViewUtil } from '../../core/utils/ViewUtil';
|
|
import { EffectEvent } from './EffectEvent';
|
|
import { EffectFinishedRelease } from './EffectFinishedRelease';
|
|
|
|
/** 特效参数 */
|
|
export interface IEffectParams {
|
|
/** 初始空间坐标 */
|
|
pos?: Vec3,
|
|
/** 初始世界坐标 */
|
|
worldPos?: Vec3,
|
|
/** 是否播放完成后删除 */
|
|
isPlayFinishedRelease?: boolean,
|
|
/** 资源包名 */
|
|
bundleName?: string
|
|
}
|
|
|
|
/**
|
|
* 动画特效对象池管理器,加载动画后自动播放,播放完后自动回收到池中
|
|
* 1、支持Spine动画
|
|
* 2、支持Cocos Animation动画
|
|
* 3、支持Cocos ParticleSystem粒子动画
|
|
*/
|
|
export class EffectSingleCase {
|
|
private static _instance: EffectSingleCase;
|
|
static get instance(): EffectSingleCase {
|
|
if (this._instance == null) {
|
|
this._instance = new EffectSingleCase();
|
|
}
|
|
return this._instance;
|
|
}
|
|
|
|
private _speed = 1;
|
|
/** 全局动画播放速度 */
|
|
get speed(): number {
|
|
return this._speed;
|
|
}
|
|
set speed(value: number) {
|
|
this._speed = value;
|
|
this.effects_use.forEach((value: boolean, key: Node) => {
|
|
this.setSpeed(key);
|
|
});
|
|
}
|
|
|
|
/** 对象池集合 */
|
|
private effects: Map<string, NodePool> = new Map();
|
|
/** 正在使用中的显示对象集合 */
|
|
private effects_use: Map<Node, boolean> = new Map();
|
|
/** 对象池中用到的资源 - 这里只管理本对象加载的资源,预加载资源由其它对象自己施放 */
|
|
private res: Map<string, string> = new Map();
|
|
|
|
constructor() {
|
|
message.on(EffectEvent.Put, this.onPut, this);
|
|
}
|
|
|
|
private onPut(event: string, node: Node) {
|
|
this.put(node);
|
|
}
|
|
|
|
/**
|
|
* 获取指定资源池中对象数量
|
|
* @param path 预制资源路径
|
|
*/
|
|
getCount(path: string): number {
|
|
const np = this.effects.get(path);
|
|
if (np) {
|
|
return np.size();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/** 池中预加载显示对象 */
|
|
preload(count: number, path: string, bundleName: string = resLoader.defaultBundleName): Promise<void> {
|
|
return new Promise(async (resolve, reject) => {
|
|
let np = this.effects.get(path);
|
|
if (np == null) {
|
|
np = new NodePool();
|
|
this.effects.set(path, np);
|
|
}
|
|
|
|
this.res.set(path, bundleName);
|
|
await resLoader.load(bundleName, path, Prefab);
|
|
|
|
for (let i = 0; i < count; i++) {
|
|
const node = ViewUtil.createPrefabNode(path, bundleName);
|
|
//@ts-ignore
|
|
node.res_path = path;
|
|
np.put(node);
|
|
}
|
|
resolve();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 加载资源并生成节点对象
|
|
* @param path 预制资源路径
|
|
* @param parent 父节点
|
|
* @param params 显示参数
|
|
*/
|
|
loadAndShow(path: string, parent?: Node, params?: IEffectParams): Promise<Node> {
|
|
return new Promise(async (resolve, reject) => {
|
|
const np = this.effects.get(path);
|
|
if (np == undefined) {
|
|
if (params && params.bundleName) {
|
|
this.res.set(path, params.bundleName);
|
|
await resLoader.load(params.bundleName, path, Prefab);
|
|
}
|
|
else {
|
|
this.res.set(path, resLoader.defaultBundleName);
|
|
await resLoader.load(path, Prefab);
|
|
}
|
|
|
|
const node = this.show(path, parent, params);
|
|
resolve(node);
|
|
}
|
|
else {
|
|
const node = this.show(path, parent, params);
|
|
resolve(node);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 显示预制对象
|
|
* @param path 预制资源路径
|
|
* @param parent 父节点
|
|
* @param params 显示参数
|
|
*/
|
|
show(path: string, parent?: Node, params?: IEffectParams): Node {
|
|
let np = this.effects.get(path);
|
|
if (np == null) {
|
|
np = new NodePool();
|
|
this.effects.set(path, np);
|
|
}
|
|
|
|
let node: Node;
|
|
// 创建池中新显示对象
|
|
if (np.size() == 0) {
|
|
let bundleName = resLoader.defaultBundleName;
|
|
if (params && params.bundleName) bundleName = params.bundleName;
|
|
node = ViewUtil.createPrefabNode(path, bundleName);
|
|
//@ts-ignore
|
|
node.res_path = path;
|
|
if (params && params.isPlayFinishedRelease) {
|
|
node.addComponent(EffectFinishedRelease);
|
|
}
|
|
}
|
|
// 池中获取没使用的显示对象
|
|
else {
|
|
node = np.get()!;
|
|
}
|
|
|
|
// 设置动画播放速度
|
|
this.setSpeed(node);
|
|
|
|
// 设置显示对象位置
|
|
if (params) {
|
|
if (params.pos) node.position = params.pos;
|
|
if (params.worldPos) node.worldPosition = params.worldPos;
|
|
}
|
|
|
|
// 显示到屏幕上
|
|
if (parent) node.parent = parent;
|
|
|
|
// 记录缓冲池中放出的节点
|
|
this.effects_use.set(node, true);
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* 回收对象
|
|
* @param name 预制对象名称
|
|
* @param node 节点
|
|
*/
|
|
put(node: Node) {
|
|
//@ts-ignore
|
|
const name = node.res_path;
|
|
if (name) {
|
|
const np = this.effects.get(name);
|
|
if (np) {
|
|
// 回收使用的节点
|
|
this.effects_use.delete(node);
|
|
|
|
// 回到到池中
|
|
np.put(node);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 清除对象池数据
|
|
* @param path 参数为空时,清除所有对象池数据;指定名时,清楚指定数据
|
|
*/
|
|
clear(path?: string) {
|
|
if (path) {
|
|
const np = this.effects.get(path);
|
|
if (np) np.clear();
|
|
}
|
|
else {
|
|
this.effects.forEach((np) => {
|
|
np.clear();
|
|
});
|
|
this.effects.clear();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 释放对象池中显示对象的资源内存
|
|
* @param path 资源路径
|
|
*/
|
|
release(path?: string) {
|
|
if (path) {
|
|
this.clear(path);
|
|
const bundleName = this.res.get(path);
|
|
resLoader.release(path, bundleName);
|
|
this.res.delete(path);
|
|
}
|
|
else {
|
|
// 施放池中对象内存
|
|
this.clear();
|
|
|
|
// 施放对象资源内存
|
|
this.res.forEach((bundleName: string, path: string) => {
|
|
resLoader.release(path, bundleName);
|
|
});
|
|
this.res.clear();
|
|
}
|
|
}
|
|
|
|
/** 设置动画速度 */
|
|
private setSpeed(node: Node) {
|
|
// SPINE动画
|
|
const spine = node.getComponent(sp.Skeleton);
|
|
if (spine) {
|
|
spine.timeScale = this.speed;
|
|
}
|
|
else {
|
|
// COCOS动画
|
|
const anims: Animation[] = node.getComponentsInChildren(Animation);
|
|
if (anims.length > 0) {
|
|
anims.forEach((animator) => {
|
|
const aniName = animator.defaultClip?.name;
|
|
if (aniName) {
|
|
const aniState = animator.getState(aniName);
|
|
if (aniState) {
|
|
aniState.speed = this.speed;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
// 粒子动画
|
|
else if (ParticleSystem) {
|
|
const particles: ParticleSystem[] = node.getComponentsInChildren(ParticleSystem);
|
|
particles.forEach((particle) => {
|
|
particle.simulationSpeed = this.speed;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|