| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- import { _decorator, Component, Node, Vec3, instantiate, UITransform, resources, sp, find, JsonAsset } from 'cc';
- const { ccclass, property } = _decorator;
- /**
- * 小球撞击动画管理器
- * 负责在小球撞击时播放特效动画
- */
- @ccclass('BallAni')
- export class BallAni extends Component {
-
- // 撞击特效预制体缓存
- private static impactEffectSkeleton: sp.SkeletonData = null;
- private static isLoading: boolean = false;
-
- // 当前播放中的特效节点列表
- private activeEffects: Node[] = [];
-
- start() {
- // 预加载撞击特效资源
- this.preloadImpactEffect();
- }
-
- /**
- * 预加载撞击特效资源
- */
- private preloadImpactEffect() {
- if (BallAni.impactEffectSkeleton || BallAni.isLoading) {
- return;
- }
-
- BallAni.isLoading = true;
- const path = 'Animation/WeaponTx/tx0005/tx0005';
- resources.load(path, sp.SkeletonData, (err, sData: sp.SkeletonData) => {
- BallAni.isLoading = false;
- if (err || !sData) {
- console.warn('[BallAni] 加载撞击特效失败:', err);
- return;
- }
- BallAni.impactEffectSkeleton = sData;
- console.log('[BallAni] 撞击特效资源加载成功');
- });
- }
-
- /**
- * 在指定位置播放撞击特效
- * @param worldPosition 世界坐标位置
- */
- public playImpactEffect(worldPosition: Vec3) {
- // 如果资源未加载,直接加载并播放
- if (!BallAni.impactEffectSkeleton) {
- const path = 'Animation/WeaponTx/tx0005/tx0005';
- resources.load(path, sp.SkeletonData, (err, sData: sp.SkeletonData) => {
- if (err || !sData) {
- console.warn('[BallAni] 加载撞击特效失败:', err);
- return;
- }
- BallAni.impactEffectSkeleton = sData;
- this.createAndPlayEffect(worldPosition, sData);
- });
- return;
- }
-
- this.createAndPlayEffect(worldPosition, BallAni.impactEffectSkeleton);
- }
-
- /**
- * 创建并播放特效
- */
- private createAndPlayEffect(worldPosition: Vec3, skeletonData: sp.SkeletonData) {
- const effectNode = new Node('ImpactEffect');
- const skeleton = effectNode.addComponent(sp.Skeleton);
- skeleton.skeletonData = skeletonData;
- skeleton.premultipliedAlpha = false;
- skeleton.setAnimation(0, 'animation', false);
- skeleton.setCompleteListener(() => {
- this.removeEffect(effectNode);
- });
-
- const canvas = find('Canvas');
- if (canvas) {
- canvas.addChild(effectNode);
- effectNode.setWorldPosition(worldPosition);
- // 设置特效缩放
- effectNode.setScale(0.8, 0.8, 1);
- // 添加到活动特效列表
- this.activeEffects.push(effectNode);
- } else {
- effectNode.destroy();
- }
- }
-
- /**
- * 移除特效节点
- * @param effectNode 要移除的特效节点
- */
- private removeEffect(effectNode: Node) {
- // 从活动特效列表中移除
- const index = this.activeEffects.indexOf(effectNode);
- if (index !== -1) {
- this.activeEffects.splice(index, 1);
- }
-
- // 销毁节点
- if (effectNode && effectNode.isValid) {
- effectNode.destroy();
- }
- }
-
- /**
- * 清理所有活动的特效
- */
- public clearAllEffects() {
- for (const effect of this.activeEffects) {
- if (effect && effect.isValid) {
- effect.destroy();
- }
- }
- this.activeEffects = [];
- }
-
- onDestroy() {
- // 组件销毁时清理所有特效
- this.clearAllEffects();
- }
-
- /**
- * 获取单例实例(如果需要全局访问)
- */
- public static getInstance(): BallAni | null {
- const gameArea = find('Canvas/GameLevelUI/GameArea');
- if (!gameArea) {
- return null;
- }
-
- let ballAni = gameArea.getComponent(BallAni);
- if (!ballAni) {
- ballAni = gameArea.addComponent(BallAni);
- }
-
- return ballAni;
- }
- }
|