Cocos Creator 3.x 实现“粒子特效” 的 点击触发

粒子特效点击触发技术实现文档

概述

本文档详细介绍了在Cocos Creator 3.x中实现粒子特效点击触发的技术方案,包括事件处理机制、组件间通信、对象池管理等关键技术点。

制作粒子特效

http://www.effecthub.com/particle2dx

制作完成后导出

第一个选项为plist格式

制作预制体

将plist拖入,注意Particle中的属性勾选。

场景节点创建


ParticleClickEffect.ts挂载到clickParticle

Game.ts挂载到Canvas

技术架构

核心组件

  1. Game.ts - 游戏主控制器,负责触摸事件监听和粒子特效触发
  2. ParticleClickEffect.ts - 粒子特效管理器,负责粒子特效的创建、播放和回收

设计模式

  • 单一职责原则:Game.ts负责事件处理,ParticleClickEffect.ts负责特效管理
  • 组件间通信:通过公共方法进行解耦合调用
  • 对象池模式:优化性能,避免频繁创建销毁节点

详细实现

1. 事件处理机制

Game.ts 触摸事件处理
typescript 复制代码
onTouchStart(event: EventTouch) {
    // 每次点击计数器加1
    this.count++;
  
    // 更新Label显示的文本
    if (this.label) {
        this.label.string = this.count.toString();
    }
  
    // 获取触摸位置
    const temp = event.getUILocation();
    const worldPosition = new Vec3(temp.x, temp.y, 0);
    const localPosition = new Vec3();
  
    // 将世界坐标转换为本地坐标
    this.node.inverseTransformPoint(localPosition, worldPosition);
  
    console.log(`Game.ts 触摸事件 - 位置: (${localPosition.x}, ${localPosition.y}), 计数: ${this.count}`);
  
    // 使用ParticleClickEffect创建粒子特效
    if (this.particleClickEffect) {
        this.particleClickEffect.createClickEffect(localPosition.x, localPosition.y);
    } else {
        // 备用方案:使用旧的createClickEffect方法
        this.createClickEffect(localPosition);
    }
}
坐标转换说明
  • event.getUILocation():获取触摸点的UI世界坐标
  • inverseTransformPoint():将世界坐标转换为节点的本地坐标系

2. 组件间通信

Game.ts 中获取ParticleClickEffect组件引用
typescript 复制代码
@property(Node)
public particleClickNode: Node = null!; // ParticleClickEffect节点

private particleClickEffect: ParticleClickEffect | null = null; // 组件引用

start() {
    // 获取ParticleClickEffect组件
    if (this.particleClickNode) {
        this.particleClickEffect = this.particleClickNode.getComponent(ParticleClickEffect);
        if (this.particleClickEffect) {
            console.log(`成功获取ParticleClickEffect组件`);
        } else {
            console.log(`未找到ParticleClickEffect组件`);
        }
    } else {
        console.log(`particleClickNode未设置`);
    }
}
ParticleClickEffect.ts 提供公共接口
typescript 复制代码
// 公共方法:供外部调用来创建粒子特效
public createClickEffect(x: number, y: number) {
    console.log(`ParticleClickEffect.createClickEffect被调用 - 坐标: (${x}, ${y})`);
    const position = new Vec3(x, y, 0);
    this.newClickNode(position);
}

3. 粒子特效管理

对象池管理
typescript 复制代码
private _clickPool: NodePool = new NodePool();

public newClickNode(position: Vec3, callBack?: (node: Node | null) => void) {
    let newNode: Node | null = null;
  
    // 优先从对象池获取节点
    if (this._clickPool.size() > 0) {
        newNode = this._clickPool.get();
        if (newNode) {
            // 重置节点状态
            newNode.active = true;
            newNode.removeFromParent();
          
            // 重置粒子系统组件状态
            const particle = newNode.getComponent(ParticleSystem2D);
            if (particle) {
                particle.stopSystem();
                particle.resetSystem();
                particle.enabled = true;
            }
          
            this.setClickNode(newNode, position, callBack);
        }
    } else {
        // 对象池为空时,异步加载预制体
        resources.load("prefab/clickParticle", Prefab, (err, prefab) => {
            if (err) {
                console.error('加载预制体失败:', err);
                if (callBack) callBack(null);
                return;
            }
            newNode = instantiate(prefab);
            this.setClickNode(newNode, position, callBack);
        });
    }
}
粒子系统状态管理
typescript 复制代码
private setClickNode(newNode: Node, position: Vec3, callBack?: (node: Node | null) => void) {
    newNode.name = "clickNode";
    newNode.setPosition(position);
    newNode.active = true;
    this.node.addChild(newNode);
  
    const particle = newNode.getComponent(ParticleSystem2D);
    if (particle) {
        // 禁用自动移除功能,确保节点可以被回收
        particle.autoRemoveOnFinish = false;
      
        // 强制重置粒子系统状态
        particle.stopSystem();
        particle.resetSystem();
      
        // 延迟一帧后播放,确保状态正确
        this.scheduleOnce(() => {
            if (particle && particle.isValid) {
                particle.enabled = true;
                particle.resetSystem();
              
                // 设置定时检查回收机制
                this.scheduleOnce(() => {
                    this.checkAndRecycleParticle(newNode, particle);
                }, 0.5);
            }
        }, 0.1);
    }
  
    if (callBack) {
        callBack(newNode);
    }
}
自动回收机制
typescript 复制代码
private checkAndRecycleParticle(node: Node, particle: ParticleSystem2D) {
    if (!node || !node.isValid || !particle || !particle.isValid) {
        return;
    }
  
    // 检查粒子数量
    if (particle.particleCount <= 0) {
        // 粒子系统已完成播放,回收节点
        if (node.parent) {
            node.removeFromParent();
        }
      
        // 重置粒子系统状态
        particle.stopSystem();
        particle.resetSystem();
        particle.enabled = false;
      
        // 重置节点状态
        node.active = false;
      
        // 回收节点到对象池
        this._clickPool.put(node);
        console.log(`粒子特效已回收 - 节点已放回对象池`);
    } else {
        // 粒子系统仍在播放,继续检查
        this.scheduleOnce(() => {
            this.checkAndRecycleParticle(node, particle);
        }, 0.1);
    }
}

关键技术点

1. 事件监听冲突解决

问题 :多个脚本同时监听同一节点的触摸事件,导致事件冲突
解决方案

  • Game.ts统一处理触摸事件
  • ParticleClickEffect.ts提供公共接口供调用
  • 消除事件监听冲突

2. 性能优化

对象池优势

  • 避免频繁创建销毁节点
  • 减少内存分配和垃圾回收
  • 提高特效播放的响应速度

粒子系统优化

  • 禁用 autoRemoveOnFinish,手动控制回收
  • 状态重置确保每次播放正常
  • 延迟播放确保状态正确

3. 错误处理

组件获取失败处理

typescript 复制代码
if (this.particleClickEffect) {
    this.particleClickEffect.createClickEffect(localPosition.x, localPosition.y);
} else {
    // 备用方案:使用旧的createClickEffect方法
    this.createClickEffect(localPosition);
}

节点状态检查

typescript 复制代码
private checkAndRecycleParticle(node: Node, particle: ParticleSystem2D) {
    if (!node || !node.isValid || !particle || !particle.isValid) {
        return;
    }
    // ... 回收逻辑
}

使用指南

1. 场景设置

  1. 在场景中创建UI节点
  2. 添加Game.ts组件到主节点
  3. 添加ParticleClickEffect.ts组件到粒子管理节点
  4. 在Game.ts组件中绑定ParticleClickEffect节点引用

2. 预制体准备

  1. 创建粒子特效预制体,路径:assets/resources/prefab/clickParticle
  2. 确保预制体包含ParticleSystem2D组件
  3. 设置合适的粒子参数和生命周期

3. 参数配置

Game.ts参数

  • particleClickNode:绑定ParticleClickEffect节点
  • label:绑定显示点击次数的Label(可选)

ParticleClickEffect.ts参数

  • 无需额外配置,自动管理对象池

4. 调试建议

  1. 启用控制台日志:查看触摸事件触发情况
  2. 检查节点状态:确保节点激活且组件正确绑定
  3. 监控对象池:查看对象池大小变化
  4. 测试连续点击:验证特效连续播放效果

常见问题解决

1. 粒子特效不显示

可能原因

  • 触摸事件未触发
  • 坐标转换错误
  • 粒子系统状态异常

解决方案

  • 检查控制台日志确认事件触发
  • 验证坐标转换逻辑
  • 检查粒子系统组件状态

2. 内存泄漏

可能原因

  • 节点未正确回收
  • 对象池未清空

解决方案

  • 确保 checkAndRecycleParticle正常执行
  • 在组件销毁时清空对象池

3. 性能问题

可能原因

  • 频繁创建销毁节点
  • 粒子数量过多

解决方案

  • 使用对象池管理节点
  • 控制同时播放的粒子数量
  • 优化粒子参数设置

扩展建议

  1. 多样化特效:支持不同类型的粒子特效
  2. 音效集成:添加点击音效播放
  3. 触觉反馈:支持设备震动反馈
  4. 性能监控:添加性能统计和优化建议
  5. 可视化编辑器:提供特效参数可视化编辑

总结

本技术方案通过合理的事件处理机制、组件间解耦合设计和高效的对象池管理,实现了稳定可靠的粒子特效点击触发功能。该方案具有良好的扩展性和维护性,适用于各类游戏和交互应用的特效需求。

相关推荐
胡童嘉6 天前
长沙烈焰鸟网络科技有限公司实习day13日记
功能测试·学习·职场和发展·游戏引擎·cocos2d
神秘的土鸡9 天前
【CS创世SD NAND征文】为无人机打造可靠数据仓:工业级存储芯片CSNP32GCR01-AOW在飞控系统中的应用实践
嵌入式硬件·游戏引擎·无人机·cocos2d·雷龙
小时候的阳光23 天前
Cocos Creator 和 Unity 3D 编辑界面字体样式大小调整
unity·cocos2d·字体大小
mit6.82424 天前
[无人机sdk] Open Protocol | 协议包构造&验证
游戏引擎·无人机·cocos2d
锦瑟弦音25 天前
2048游戏开发笔记4 & 音效 cocos3.8.7
笔记·typescript·cocos2d
FairGuard手游加固1 个月前
Cocos资源加密方案解析
安全·游戏·cocos2d
应用市场1 个月前
无人机编队飞行原理与Python仿真实现完整指南
python·无人机·cocos2d
云卓SKYDROID1 个月前
无人机中继器模式技术对比
人工智能·游戏引擎·php·无人机·cocos2d·高科技·云卓科技
重生之我在永职2 个月前
cocos 添加背景,帧动画,贴图
cocos2d