cocoscreator事件
cocos creator 事件
在做一个消除类游戏时,需要对点击的方块做出响应。代码很简单,可背后的原理还多着呢。
1. 普通节点注册click事件
在cc中如果需要相应click事件,需要为该节点添加一个Button组件。或使用类似效果的事件比如
-
cc.Node.EventType.MOUSE_DOWN
-
cc.Node.EventType.TOUCH_END
//author herbert qq:464884492 //注册按钮click事件 btn.node.on("click", event=>{cc.log("button click")}); //注册MOUSE_DOWN btn.node.on(cc.Node.EventType.MOUSE_DOWN,event=>{cc.log("button MOUSE_DOWN")}); //注册TOUCH_END btn.node.on(cc.Node.EventType.TOUCH_END,event=>{cc.log("button TOUCH_END")})
2. 应该减少事件注册量
是否没有问题了?在写juqery时,有事件委托(delegate)的概念。啥意思呢,就是在节点的父级注册事件,来响应子节点的事件源。为啥可以实现,主要归功于js事件的两大机制
-
事件冒泡,事件响应从子节点往上冒泡到顶层节点
-
事件捕获,事件响应冲顶层节点依次传递到最末级节点
所以问题来了,消除类游戏都是通过预制资源生成不同样式的方块。若在每一方块上都注册事件,势必导致内存上涨(虽然现在内存很大了)。看看cc文档,事件机制完全是一样的(最终都是JS),然而我想在我的Canvas上注册一个click事件,问题出现了。
3.问题来了
问题就是我在Canvas上注册了click事件,点击button时,Canvas 上居然没有收到我的click事件。由此我查看cc源码,写了一堆测试代码,最总得出以下结
-
click事件确实Button组件特殊存
-
click事件不会向上或向下传递
-
node.emit触发事件不会向上或向下传递
-
node.dispatchEvent支持事件向上或向下传递
-
使用node.dispatchEvent参数必须是 cc.Event.EventCustom对象
4.click事件特殊在哪里
cc.Button 组件中的click事件,其实是cc的自定义事件,源码为证
//author:herbert wx:464884492 ... this.node.on(cc.Node.EventType.TOUCH_END, this._onTouchEnded, this); ... _onTouchEnded (event) { if (!this.interactable || !this.enabledInHierarchy) return; if (this._pressed) { cc.Component.EventHandler.emitEvents(this.clickEvents, event); this.node.emit('click', this);//触发事件 } this._pressed = false; this._updateState(); event.stopPropagation(); //停止冒泡 }, ...
所以,之所Button能响应click事件,是因为组件注册了TOUCH_END事件,并在响应该事件函数中发射一个click事件。
5. javascript 自定义事件
参考mdn文档,js自定事件方式如下
// author:herbert wx:464884492 <script text="javascript"> let cusEvent = new Event("custom", { bubbles: true //允许冒泡 }); document.body.addEventListener("custom", e => { console.log("自定义事件"); console.log(" Body event by custom"); }); let btn = document.querySelector("#btn"); btn.addEventListener("custom", e => { console.log("自定义事件"); console.log("Button event by custom"); }) btn.dispatchEvent(cusEvent); </script>
5.了解下cc.node.emit
cc.node.emit 最终调用的是CallbacksInvoker.prototype.invoke 方法,从源码来看,是从对应的缓存对象中找到注册的回调方法,依次调用回调函数。
//author herbert wx:464884492 CallbacksInvoker.prototype.invoke = function (key, p1, p2, p3, p4, p5) { var list = this._callbackTable[key]; if (list) { var rootInvoker = !list.isInvoking; list.isInvoking = true; var callbacks = list.callbacks; var targets = list.targets; for (var i = 0, len = callbacks.length; i < len; ++i) { var callbmhtack = callbacks[i]; if (callback) { var target = targets[i]; if (target) { callback.call(target, p1, p2, p3, p4, p5); } else { callback(p1, p2, p3, p4, p5); } } } if (rootInvoker) { list.isInvoking = false; if (list.containCanceled) { list.purgeCanceled(); } }}};
所以click自然不会往上或往下传递。
6.dispatchEvent,事件冒泡
dispatchEvent 利用自定义事件的 bubbles 属性,实现冒泡。至于为啥使用 btn.node.dispatchEvent(new cc.Event.EventMouse(cc.Node.EventType.MOUSE_DOWN, true))
没有触发事件是因为cc在底层,将事件类型统一改成了 cc.Event.MOUSE
,源码为证
author:herbert wx:464884492 ... var EventMouse = function (eventType, bubbles) { cc.Event.call(this, cc.Event.MOUSE, bubbles); ... };
场景
运行效果
7.总结
做开发,不管是开发游戏还是其他应用程序。思路基本是一样的。在简单的事,多想想,再发散一下,你会收获更多。
需要进cocos游戏开发群的朋友,请添加我微信回复cocos
欢迎感兴趣的朋友关注我的订阅号“小院不小”,或点击下方二维码关注。我将多年开发中遇到的难点,以及一些有意思的功能,体会都会一一发布到我的订阅号中。如需本文demo请在订阅号中回复ccevent
- 转载请注明来源
- 作者:杨瀚博
- QQ:464884492
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤