cocoscreator事件


cocos creator 事件

在做一個消除類游戲時,需要對點擊的方塊做出響應。代碼很簡單,可背后的原理還多着呢。

1. 普通節點注冊click事件

在cc中如果需要相應click事件,需要為該節點添加一個Button組件。或使用類似效果的事件比如

  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事件的兩大機制

  1. 事件冒泡,事件響應從子節點往上冒泡到頂層節點

  2. 事件捕獲,事件響應沖頂層節點依次傳遞到最末級節點

所以問題來了,消除類游戲都是通過預制資源生成不同樣式的方塊。若在每一方塊上都注冊事件,勢必導致內存上漲(雖然現在內存很大了)。看看cc文檔,事件機制完全是一樣的(最終都是JS),然而我想在我的Canvas上注冊一個click事件,問題出現了。

3.問題來了

問題就是我在Canvas上注冊了click事件,點擊button時,Canvas 上居然沒有收到我的click事件。由此我查看cc源碼,寫了一堆測試代碼,最總得出以下結

  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自定事件方式如下

// 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

訂閱號


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM