当前位置: 首页 > news >正文

CocosCreator 事件系统全解析:从基础监听、冒泡捕获到实战应用 (第五篇)

1. 事件监听与关闭:从入门到精通

刚接触CocosCreator时,我发现很多新手最困惑的就是事件监听机制。其实理解起来很简单,就像给家里的门铃安装一个接收器——当有人按门铃(触发事件)时,接收器(监听函数)就会发出响声(执行回调)。

在CocosCreator中,最基础的事件监听方式是使用this.node.on()方法。我特别喜欢它的第三个参数target,这个设计真的很贴心。比如下面这两种写法效果完全一样:

// 写法一:使用bind this.node.on('mousedown', function(event) { this.node.color = cc.Color.RED; }.bind(this)); // 写法二:使用target参数 this.node.on('mousedown', function(event) { this.node.color = cc.Color.RED; }, this);

在实际项目中,我更推荐使用第二种写法。因为使用bind会创建一个新函数,这在频繁注册/注销事件时可能会影响性能。而使用target参数则更高效,代码也更简洁。

事件关闭是很多开发者容易忽略的部分。我见过不少项目因为忘记关闭事件监听而导致内存泄漏。正确的做法是在onDisableonDestroy生命周期中调用off方法:

onDisable: function() { // 必须保证参数与on完全一致 this.node.off('mousedown', this.callback, this); }

这里有个坑我踩过:如果回调函数是匿名函数,就无法正确关闭监听。所以一定要像上面这样,把回调函数定义为类方法。

2. 触摸事件:移动开发的核心

触摸事件是移动游戏开发的重中之重。CocosCreator的巧妙之处在于,它统一处理了移动端的触摸和PC端的鼠标事件。这意味着你只需要写一套代码,就能适配两种平台。

触摸事件有四种类型,我用一个表格来总结它们的区别:

事件类型触发时机典型应用场景
TOUCH_START手指接触屏幕开始拖拽、按钮按下效果
TOUCH_MOVE手指在屏幕上移动拖拽物体、绘制轨迹
TOUCH_END手指离开屏幕结束拖拽、确认点击
TOUCH_CANCEL手指在区域外离开取消操作、恢复初始状态

处理触摸事件时,event.getLocation()event.getDelta()是最常用的API。比如实现一个拖拽功能:

this.node.on('touchmove', function(event) { let delta = event.getDelta(); this.node.x += delta.x; this.node.y += delta.y; }.bind(this));

多点触控是进阶功能,通过event.getID()可以区分不同的触点。我曾经用这个特性实现了一个双指缩放的功能,核心代码如下:

let startDistance = 0; this.node.on('touchstart', function(event) { if(event.getAllTouches().length === 2) { let touch1 = event.getTouchByIndex(0); let touch2 = event.getTouchByIndex(1); startDistance = cc.Vec2.distance(touch1.getLocation(), touch2.getLocation()); } }); this.node.on('touchmove', function(event) { if(event.getAllTouches().length === 2) { // 计算当前两指距离并缩放节点 } });

3. 鼠标事件:PC端交互的灵魂

虽然触摸事件在移动端很强大,但在PC端游戏开发中,鼠标事件才是主角。CocosCreator提供了完整的鼠标事件支持,包括点击、移动、滚轮等。

鼠标事件有个特别有用的特性:mouseentermouseleave。这两个事件不需要点击,只要鼠标移入移出就会触发,非常适合实现悬停效果:

this.node.on('mouseenter', function() { this.node.scale = 1.2; // 悬停放大效果 }, this); this.node.on('mouseleave', function() { this.node.scale = 1.0; // 恢复原大小 }, this);

鼠标滚轮事件处理有个小技巧。event.getScrollY()返回的是滚轮滚动的Y轴距离,但这个值在不同浏览器中可能正负相反。我通常这样处理:

this.node.on('mousewheel', function(event) { let delta = -event.getScrollY() / 120; // 标准化滚轮值 this.node.scale += delta * 0.1; }, this);

在实际项目中,我经常需要区分鼠标左右键。通过event.getButton()可以获取按下的按钮:

this.node.on('mousedown', function(event) { if(event.getButton() === cc.Event.EventMouse.BUTTON_RIGHT) { // 右键菜单逻辑 } }, this);

4. 键盘与重力感应:全局事件处理

键盘和重力感应事件属于全局事件,需要通过cc.systemEvent来监听。这类事件的处理方式与节点事件略有不同。

键盘事件最常用于角色控制。下面是一个典型的WASD移动实现:

onLoad: function() { cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this); }, onKeyDown: function(event) { switch(event.keyCode) { case cc.macro.KEY.w: this.player.y += 10; break; case cc.macro.KEY.s: this.player.y -= 10; break; // 其他按键处理... } }

重力感应事件需要先启用加速度计。在手机游戏中,我常用它来控制赛车或平衡球:

onLoad: function() { cc.systemEvent.setAccelerometerEnabled(true); cc.systemEvent.on(cc.SystemEvent.EventType.DEVICEMOTION, this.onMotion, this); }, onMotion: function(event) { let acc = event.acc; this.ball.x += acc.x * 10; // 注意:Y轴在手机上通常是上下方向 this.ball.y += acc.y * 10; }

这里有个重要提示:不同设备的加速度计数据可能有差异,最好在实际设备上测试并添加数据过滤:

// 简单的低通滤波,减少抖动 this.filteredAccX = this.filteredAccX * 0.8 + event.acc.x * 0.2;

5. 自定义事件:组件通信的利器

当项目规模变大时,节点之间的通信就成了挑战。CocosCreator提供了强大的自定义事件系统,我总结出两种主要使用场景。

场景一:简单通知使用emit方法最适合组件内部的简单通信:

// 发送端 this.node.emit('score-update', 100); // 接收端 this.node.on('score-update', function(score) { this.scoreLabel.string = score; }, this);

场景二:跨节点通信当事件需要在节点树中传递时,dispatchEvent就派上用场了:

// 创建并派发事件 let event = new cc.Event.EventCustom('item-selected', true); event.detail = {id: 123}; this.node.dispatchEvent(event); // 在父节点监听 parentNode.on('item-selected', function(event) { let itemId = event.detail.id; // 处理逻辑... });

我在一个商城项目中大量使用了这种模式,使得商品选择、购物车更新等逻辑完全解耦。

6. 事件冒泡与捕获:深入事件机制

理解事件冒泡和捕获是掌握CocosCreator事件系统的关键。我画了个示意图帮助理解:

捕获阶段:父节点 -> 子节点 目标阶段:当前节点 冒泡阶段:子节点 -> 父节点

默认情况下,事件监听都是在冒泡阶段触发的。如果想让父节点先于子节点处理事件,就需要使用捕获阶段:

// 第四个参数true表示使用捕获阶段 parentNode.on('touchstart', function() { console.log('父节点先执行'); }, this, true);

这个特性在实现一些特殊UI时非常有用。比如我做过一个卡片游戏,需要在卡片被拖动时先由牌桌处理:

// 牌桌节点 tableNode.on('touchstart', function() { // 检查是否可以拖动 }, this, true);

停止传播是另一个重要概念。event.stopPropagation()会阻止事件继续冒泡,而stopPropagationImmediate()还会阻止当前节点的其他监听器执行。

7. 实战案例:拼图游戏

让我们用一个完整的拼图游戏案例,串联前面学到的所有知识点。这个游戏会用到触摸、自定义事件、事件冒泡等多种技术。

核心功能实现:

  1. 拼图块拖动(触摸事件)
this.node.on('touchmove', function(event) { let delta = event.getDelta(); this.node.x += delta.x; this.node.y += delta.y; // 检查是否拼接到正确位置 if(this.checkPosition()) { this.node.emit('piece-complete'); } }, this);
  1. 游戏状态管理(自定义事件)
// 当所有拼图完成时 this.node.on('all-complete', function() { this.showSuccess(); }, this); // 在拼图块中 this.node.emit('piece-complete');
  1. 边界限制(事件冒泡)
// 游戏区域节点 gameArea.on('touchmove', function(event) { if(!this.checkBoundary(event.getLocation())) { event.stopPropagation(); } }, this, true);

这个案例展示了如何将各种事件类型有机结合起来,构建复杂的交互逻辑。在实际开发中,合理使用事件系统可以让代码结构更清晰,各模块职责更明确。

http://www.jsqmd.com/news/793852/

相关文章:

  • Android 14 + Linux 6.1 平台 RTL8922AE 蓝牙适配实战:从无法启动到成功拉起
  • Docker Compose智能副驾驶:用自然语言管理容器编排
  • PhishGuard:多层检测机制防范钓鱼网站,保护你的在线安全
  • 混合量子-经典工作流编排的云原生实践
  • Spring Boot 与 GraphQL 集成最佳实践:构建现代化 API
  • 本地化RAG智能搜索工具Fyin:Rust实现、部署与调优指南
  • Linux DRM驱动入门:手把手教你用drm_gem_cma_helper写一个最简单的dumb buffer驱动
  • Vibe Coding:现代前端开发工具链集成与工程化实践
  • Xilinx SRIO Gen2时钟架构深度解析:从参考时钟到GT共享的实战指南
  • DO-254合规开发与Model-Based Design技术解析
  • AI辅助开发在Android应用中的实践与探索
  • Arm生命周期管理器(LCM)架构与安全供应实战解析
  • Wi-Fi 6核心技术解析与高密度部署实践
  • Sigma规则驱动:自动化网络空间测绘与威胁狩猎实战指南
  • 老模块新玩法:三菱FX2N-2AD模块的精度调校与抗干扰实战指南(附电容滤波配置)
  • Maya摄影机实战:从基础创建到电影级景深应用
  • Word 2016 排版进阶(1): 巧用域代码批量处理交叉引用格式
  • primer-cli:AI就绪项目脚手架,标准化AI协作开发流程
  • Transmission密码安全加固:从配置文件到命令行实战
  • 数据压缩技术:原理、算法与应用实践
  • 超越手册:用Silvaco Atlas的MOBILITY语句调参,优化你的MOSFET跨导仿真
  • Qt项目实战:用QCustomPlot 2.1.0 + OpenGL搞定20万点实时频谱图(附FreeGLUT配置避坑)
  • AI Agent论文精选与学习指南:从规划推理到多智能体协作
  • 告别路径烦恼:一个os.path.join()让你的Python配置文件随处可读
  • 【Keras+TensorFlow+Yolo3】从零构建自定义目标检测模型:实战标注、训练与部署(TF2避坑指南)
  • 别再只盯着I2C了!SMBus协议详解:从智能电池到传感器,嵌入式开发的隐藏利器
  • Arm CoreSight SoC-400调试跟踪系统架构与应用解析
  • Windows HEIC缩略图终极指南:3分钟让iPhone照片在资源管理器完美预览
  • 压缩感知在机械振动监测中的应用与优化
  • OpenLLMetry:基于OpenTelemetry的LLM应用可观测性实践指南