310 lines
11 KiB
TypeScript
310 lines
11 KiB
TypeScript
|
import { _decorator, Node, Prefab, AnimationComponent, ParticleSystemComponent, Vec3, find, AnimationState, AnimationClip, director } from 'cc';
|
|||
|
import { PoolManager } from './poolManager';
|
|||
|
import { ResourceUtil } from './resourceUtil';
|
|||
|
|
|||
|
const { ccclass, property } = _decorator;
|
|||
|
|
|||
|
@ccclass('EffectManager')
|
|||
|
export class EffectManager{
|
|||
|
private _ndParent: Node = null!;
|
|||
|
public get ndParent() {
|
|||
|
if (!this._ndParent) {
|
|||
|
let ndEffectParent = find("effectManager") as Node;
|
|||
|
|
|||
|
if (ndEffectParent) {
|
|||
|
this._ndParent = ndEffectParent;
|
|||
|
} else {
|
|||
|
// console.warn("请在场景里添加effectManager节点");
|
|||
|
this._ndParent = new Node("effectManager");
|
|||
|
director.getScene()?.addChild(this._ndParent);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return this._ndParent;
|
|||
|
}
|
|||
|
|
|||
|
static _instance: EffectManager;
|
|||
|
|
|||
|
static get instance () {
|
|||
|
if (this._instance) {
|
|||
|
return this._instance;
|
|||
|
}
|
|||
|
|
|||
|
this._instance = new EffectManager();
|
|||
|
return this._instance;
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 播放动画
|
|||
|
* @param {string} path 动画节点路径
|
|||
|
* @param {string} aniName
|
|||
|
* @param {vec3} worPos 世界坐标
|
|||
|
* @param {boolean} isLoop 是否循环
|
|||
|
* @param {boolean} isRecycle 是否回收
|
|||
|
* @param {number} [scale=1] 缩放倍数
|
|||
|
* @param {Function} [callback=()=>{}] 回调函数
|
|||
|
*/
|
|||
|
public playAni (path: string, aniName: string, worPos: Vec3 = new Vec3(), isLoop: boolean = false, isRecycle: boolean = false, scale: number = 1, callback: Function = ()=>{}) {
|
|||
|
let childName: string = path.split("/")[1];
|
|||
|
let ndEffect: Node | null = this.ndParent.getChildByName(childName);
|
|||
|
|
|||
|
let cb = ()=>{
|
|||
|
ndEffect?.setScale(scale, scale, scale);
|
|||
|
ndEffect?.setWorldPosition(worPos);
|
|||
|
let ani: AnimationComponent= ndEffect?.getComponent(AnimationComponent) as AnimationComponent;
|
|||
|
ani.play(aniName);
|
|||
|
let aniState: AnimationState= ani.getState(aniName) as AnimationState;
|
|||
|
if (aniState) {
|
|||
|
if (isLoop) {
|
|||
|
aniState.wrapMode = AnimationClip.WrapMode.Loop;
|
|||
|
} else {
|
|||
|
aniState.wrapMode = AnimationClip.WrapMode.Normal;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
ani.once(AnimationComponent.EventType.FINISHED, ()=>{
|
|||
|
callback && callback();
|
|||
|
if (isRecycle && ndEffect) {
|
|||
|
PoolManager.instance.putNode(ndEffect);
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
if (!ndEffect) {
|
|||
|
ResourceUtil.loadEffectRes(path).then((prefab: unknown)=>{
|
|||
|
ndEffect = PoolManager.instance.getNode(prefab as Prefab, this.ndParent) as Node;
|
|||
|
ndEffect.setScale(scale, scale, scale);
|
|||
|
ndEffect.setWorldPosition(worPos);
|
|||
|
cb();
|
|||
|
})
|
|||
|
} else {
|
|||
|
cb();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 移除特效
|
|||
|
* @param {string} name 特效名称
|
|||
|
* @param {Node}} ndParent 特效父节点
|
|||
|
*/
|
|||
|
public removeEffect (name: string, ndParent: Node = this.ndParent) {
|
|||
|
let ndEffect: Node | null = ndParent.getChildByName(name);
|
|||
|
if (ndEffect) {
|
|||
|
let arrAni: AnimationComponent[] = ndEffect.getComponentsInChildren(AnimationComponent);
|
|||
|
arrAni.forEach((element: AnimationComponent)=>{
|
|||
|
element.stop();
|
|||
|
})
|
|||
|
|
|||
|
let arrParticle: [] = ndEffect?.getComponentsInChildren(ParticleSystemComponent) as any;
|
|||
|
arrParticle.forEach((element:ParticleSystemComponent)=>{
|
|||
|
element?.clear();
|
|||
|
element?.stop();
|
|||
|
})
|
|||
|
PoolManager.instance.putNode(ndEffect);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 播放粒子特效
|
|||
|
* @param {string} path 特效路径
|
|||
|
* @param {vec3}worPos 特效世界坐标
|
|||
|
* @param {number} [recycleTime=0] 特效节点回收时间,如果为0,则使用默认duration
|
|||
|
* @param {number} [scale=1] 缩放倍数
|
|||
|
* @param {vec3} eulerAngles 特效角度
|
|||
|
* @param {Function} [callback=()=>{}] 回调函数
|
|||
|
*/
|
|||
|
public playParticle (path: string, worPos: Vec3, recycleTime: number = 0, scale: number = 1, eulerAngles?: Vec3 | null, callback?: Function) {
|
|||
|
ResourceUtil.loadEffectRes(path).then((prefab: any)=>{
|
|||
|
let ndEffect: Node = PoolManager.instance.getNode(prefab as Prefab, this.ndParent) as Node;
|
|||
|
ndEffect.setScale(scale, scale, scale);
|
|||
|
ndEffect.setWorldPosition(worPos);
|
|||
|
|
|||
|
if (eulerAngles) {
|
|||
|
ndEffect.eulerAngles = eulerAngles;
|
|||
|
}
|
|||
|
|
|||
|
let maxDuration: number = 0;
|
|||
|
|
|||
|
let arrParticle: ParticleSystemComponent[]= ndEffect.getComponentsInChildren(ParticleSystemComponent);
|
|||
|
arrParticle.forEach((item: ParticleSystemComponent)=>{
|
|||
|
item.simulationSpeed = 1;
|
|||
|
item?.clear();
|
|||
|
item?.stop();
|
|||
|
item?.play()
|
|||
|
|
|||
|
let duration: number= item.duration;
|
|||
|
maxDuration = duration > maxDuration ? duration : maxDuration;
|
|||
|
})
|
|||
|
|
|||
|
let seconds: number = recycleTime && recycleTime > 0 ? recycleTime : maxDuration;
|
|||
|
|
|||
|
setTimeout(()=>{
|
|||
|
if (ndEffect.parent) {
|
|||
|
callback && callback();
|
|||
|
PoolManager.instance.putNode(ndEffect);
|
|||
|
}
|
|||
|
}, seconds * 1000)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 播放节点下面的动画和粒子
|
|||
|
*
|
|||
|
* @param {Node} targetNode 特效挂载节点
|
|||
|
* @param {string} effectPath 特效路径
|
|||
|
* @param {boolean} [isPlayAni=true] 是否播放动画
|
|||
|
* @param {boolean} [isPlayParticle=true] 是否播放特效
|
|||
|
* @param {number} [recycleTime=0] 特效节点回收时间,如果为0,则使用默认duration
|
|||
|
* @param {number} [scale=1] 缩放倍数
|
|||
|
* @param {Vec3} [pos=new Vec3()] 位移
|
|||
|
* @param {boolean} [isRecycle=true] 回收或者销毁
|
|||
|
* @param {Function} [callback=()=>{}] 回调函数
|
|||
|
* @returns
|
|||
|
* @memberof EffectManager
|
|||
|
*/
|
|||
|
public playEffect (targetNode: Node, effectPath: string, isPlayAni: boolean = true, isPlayParticle: boolean = true, recycleTime: number = 0, scale: number = 1, pos?: Vec3 | null, eulerAngles?: Vec3 | null, isRecycle: boolean = true, callback?: Function | null) {
|
|||
|
if (!targetNode || !targetNode.parent) {//父节点被回收的时候不播放
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
ResourceUtil.loadEffectRes(effectPath).then((prefab: any)=>{
|
|||
|
let ndEffect: Node = PoolManager.instance.getNode(prefab as Prefab, targetNode) as Node;
|
|||
|
ndEffect.setScale(scale, scale, scale);
|
|||
|
|
|||
|
if (pos) {
|
|||
|
ndEffect.setPosition(pos);
|
|||
|
}
|
|||
|
|
|||
|
if (eulerAngles) {
|
|||
|
ndEffect.eulerAngles = eulerAngles;
|
|||
|
}
|
|||
|
|
|||
|
let maxDuration: number = 0;
|
|||
|
|
|||
|
if (isPlayAni) {
|
|||
|
let arrAni: AnimationComponent[] = ndEffect.getComponentsInChildren(AnimationComponent);
|
|||
|
|
|||
|
if (arrAni.length) {
|
|||
|
arrAni.forEach((element: AnimationComponent, idx: number)=>{
|
|||
|
element?.play();
|
|||
|
|
|||
|
let aniName = element?.defaultClip?.name;
|
|||
|
if (aniName) {
|
|||
|
let aniState = element.getState(aniName);
|
|||
|
if (aniState) {
|
|||
|
aniState.time = 0;
|
|||
|
aniState.sample();
|
|||
|
|
|||
|
let duration = aniState.duration;
|
|||
|
maxDuration = duration > maxDuration ? duration : maxDuration;
|
|||
|
|
|||
|
aniState.speed = 1;
|
|||
|
}
|
|||
|
}
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (isPlayParticle) {
|
|||
|
let arrParticle: ParticleSystemComponent[]= ndEffect.getComponentsInChildren(ParticleSystemComponent);
|
|||
|
|
|||
|
if (arrParticle.length) {
|
|||
|
arrParticle.forEach((element:ParticleSystemComponent)=>{
|
|||
|
element.simulationSpeed = 1;
|
|||
|
element?.clear();
|
|||
|
element?.stop();
|
|||
|
element?.play()
|
|||
|
|
|||
|
let duration: number= element.duration;
|
|||
|
maxDuration = duration > maxDuration ? duration : maxDuration;
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
let seconds: number = recycleTime && recycleTime > 0 ? recycleTime : maxDuration;
|
|||
|
|
|||
|
setTimeout(()=>{
|
|||
|
if (ndEffect.parent) {
|
|||
|
callback && callback();
|
|||
|
if (isRecycle) {
|
|||
|
PoolManager.instance.putNode(ndEffect);
|
|||
|
} else {
|
|||
|
ndEffect.destroy();
|
|||
|
}
|
|||
|
}
|
|||
|
}, seconds * 1000)
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 播放节点上的粒子特效/托尾粒子特效
|
|||
|
*
|
|||
|
* @param {Node} ndParent
|
|||
|
* @memberof EffectManager
|
|||
|
*/
|
|||
|
public playTrail (ndParent: Node, recycleTime:number = 0, callback?:Function, speed: number = 1) {
|
|||
|
let maxDuration: number = 0;
|
|||
|
|
|||
|
if (!ndParent.active) {
|
|||
|
ndParent.active = true;
|
|||
|
}
|
|||
|
|
|||
|
let arrParticle: ParticleSystemComponent[]= ndParent.getComponentsInChildren(ParticleSystemComponent);
|
|||
|
arrParticle.forEach((element:ParticleSystemComponent)=>{
|
|||
|
element.simulationSpeed = speed;
|
|||
|
element?.clear();
|
|||
|
element?.stop();
|
|||
|
element?.play();
|
|||
|
|
|||
|
let duration: number= element.duration;
|
|||
|
maxDuration = duration > maxDuration ? duration : maxDuration;
|
|||
|
})
|
|||
|
|
|||
|
if (callback) {
|
|||
|
let seconds: number = recycleTime && recycleTime > 0 ? recycleTime : maxDuration;
|
|||
|
|
|||
|
setTimeout(()=>{
|
|||
|
callback();
|
|||
|
}, seconds * 1000)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* 播放道具消失特效
|
|||
|
* @param {string} path 特效路径
|
|||
|
* @param {vec3}worPos 特效世界坐标
|
|||
|
* @param {Function} [callback=()=>{}] 回调函数
|
|||
|
*/
|
|||
|
public playDisappearEff (path: string, worPos: Vec3, cb: Function) {
|
|||
|
ResourceUtil.loadEffectRes(path).then((prefab: any)=>{
|
|||
|
let ndEffect: Node = PoolManager.instance.getNode(prefab as Prefab, this.ndParent) as Node;
|
|||
|
ndEffect.setWorldPosition(worPos);
|
|||
|
|
|||
|
let maxDuration: number = 0;
|
|||
|
|
|||
|
let arrParticle: ParticleSystemComponent[]= ndEffect.getComponentsInChildren(ParticleSystemComponent);
|
|||
|
arrParticle.forEach((item: ParticleSystemComponent)=>{
|
|||
|
item.simulationSpeed = 1;
|
|||
|
item?.clear();
|
|||
|
item?.stop();
|
|||
|
item?.play()
|
|||
|
|
|||
|
let duration: number= item.duration;
|
|||
|
maxDuration = duration > maxDuration ? duration : maxDuration;
|
|||
|
})
|
|||
|
|
|||
|
setTimeout(()=>{
|
|||
|
if (ndEffect && ndEffect.parent) {
|
|||
|
PoolManager.instance.putNode(ndEffect);
|
|||
|
}
|
|||
|
}, maxDuration * 1000)
|
|||
|
|
|||
|
cb && cb(()=>{
|
|||
|
if (ndEffect && ndEffect.parent) {
|
|||
|
PoolManager.instance.putNode(ndEffect);
|
|||
|
}
|
|||
|
});
|
|||
|
})
|
|||
|
}
|
|||
|
}
|