cocos creator 事件

cocos creator 事件

在作一个消除类游戏时,须要对点击的方块作出响应。代码很简单,可背后的原理还多着呢。javascript

1. 普通节点注册click事件

在cc中若是须要相应click事件,须要为该节点添加一个Button组件。或使用相似效果的事件好比java

  1. cc.Node.EventType.MOUSE_DOWN
  2. 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事件的两大机制node

  1. 事件冒泡,事件响应从子节点往上冒泡到顶层节点
  2. 事件捕获,事件响应冲顶层节点依次传递到最末级节点

因此问题来了,消除类游戏都是经过预制资源生成不一样样式的方块。若在每一方块上都注册事件,势必致使内存上涨(虽然如今内存很大了)。看看cc文档,事件机制彻底是同样的(最终都是JS),然而我想在个人Canvas上注册一个click事件,问题出现了。git

3.问题来了

问题就是我在Canvas上注册了click事件,点击button时,Canvas 上竟然没有收到个人click事件。由此我查看cc源码,写了一堆测试代码,最终得出如下结github

  1. click事件确实Button组件特殊存
  2. click事件不会向上或向下传递
  3. node.emit触发事件不会向上或向下传递
  4. node.dispatchEvent支持事件向上或向下传递
  5. 使用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自定事件方式以下markdown

// 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>
复制代码

6.了解下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天然不会往上或往下传递。oop

7.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);
 ...
};
复制代码

场景

场景布局

运行效果

测试结果

8.总结

作开发,无论是开发游戏仍是其余应用程序。思路基本是同样的。再简单的事,多想一想,再发散一下,你会收获更多。 须要进cocos游戏开发群的朋友,请添加我微信回复cocos

微信群
欢迎感兴趣的朋友关注个人订阅号“小院不小”,或点击下方二维码关注。我将多年开发中遇到的难点,以及一些有意思的功能,体会都会一一发布到个人订阅号中。如需本文demo请在订阅号中回复 ccevent
订阅号
相关文章
相关标签/搜索