這兩天在使用cocos2d-js作一個拔蘿蔔遊戲,研究了一番cocos2d的事件分發機制,總結分享一下。函數
Cocos2d-JS v3.x中事件分發機制進行了重寫,事件能夠與任意對象綁定,而不是隻有Layer才能獲取。對象建立本身的事件監聽器,而後加入到全局的事件管理器統一管理。this
事件監聽器有如下幾種:url
觸摸事件spa
鍵盤響應事件code
鼠標響應事件對象
自定義事件隊列
加速計事件遊戲
在瞭解事件分發機制以前,咱們首先要明確什麼是事件分發。事件
對於事件分發,cocos2d官方定義爲:當事件發生(例如,用戶觸摸屏幕,或者敲鍵盤),EventDispatcher 會發布(Event objects)事件對象到合適的EventListeners,並調用你的回調。各個Event object包含事件的信息(好比,觸摸點所在的座標)。ip
個人理解是對於一個事件(好比觸摸事件、鍵盤相應事件等)能夠與任意對象綁定,那麼當這個事件被用戶觸發時,此時應該執行哪個對象的回調函數(好比此時咱們在好幾個sprite上同時綁定了touch事件,用戶此時點擊屏幕,用戶此時想點擊的究竟是哪個sprite),咱們就須要做出判斷。EventDispatcher作的就是這個事情。
以touch事件(觸摸事件)爲例,判斷用戶點擊的是哪個sprite的方法很簡單,其實就是在onTouchBegan方法中獲取點擊點的座標pos,而後經過cc.rectContainsPoint(target.getBoundingBox(),pos)判斷點擊的點是否在SushiSprite上。不過此時又會出現另一個問題,就是若是兩個sprite有相互重疊的部分,而此時用戶點擊的偏偏是重疊部分,那麼怎麼判斷到底點擊的是哪個sprite呢?這裏是經過priority(分爲兩種:SceneGraphPriority和FixedPriority)來解決的,優先級高的sprite優先執行它所對應的事件監聽器的回調函數。這樣就造成了一個按照優先級高低排列的sprite隊列等待依次執行用戶觸發的事件,而這中間則經過swallowTouches(吞沒事件)屬性來控制是否繼續向優先級低的sprite傳遞事件。這就造成了一個完整的事件分發機制。
tip:
SceneGraphPriority(顯示優先級):根據屏幕顯示的「遮蓋」實際狀況,進行有序的函數回調。zOrder越大,優先級越大。
FixedPriority(固定優先級):依據手動設定的 Priority 值來決定事件相應的優先級,值越小優先級越高
總結一下:
經過點擊位置進行點擊範圍判斷,來肯定執行哪個sprite的事件監聽器
若是該位置存在重疊的sprite綁定了相同的事件,則依據優先級(SceneGraphPriority顯示優先級或FixedPriority固定優先級)來順序執行函數回調
經過設置swallowTouches屬性爲true,並在onTouchBegan中返回true或者false來決定是否阻止事件的順序傳遞。若是onTouchBegan返回true,且swallowTouches爲true,則事件被吞沒,事件的順序傳遞則被阻止。
新建一個sprite,併爲其添加一個touch事件:
var SushiSprite = cc.Sprite.extend({ onEnter:function () { cc.log("onEnter"); this._super(); }, onExit:function () { cc.log("onExit"); } }); addTouchEventListenser:function(){ this.touchListener = cc.EventListener.create({ event: cc.EventListener.TOUCH_ONE_BY_ONE, // When "swallow touches" is true, then returning 'true' from the onTouchBegan method will "swallow" the touch event, preventing other listeners from using it. swallowTouches: true, //onTouchBegan event callback function onTouchBegan: function (touch, event) { var pos = touch.getLocation(); var target = event.getCurrentTarget(); if ( cc.rectContainsPoint(target.getBoundingBox(),pos)) { cc.log("touched") return true; } return false; } cc.eventManager.addListener(this.touchListener,this); });
上面的代碼:
首先經過使用cc.EventListener.create建立了一個Touch事件監聽器touchListener
而後,經過cc.eventManager.addListener註冊監聽器到事件管理器。cc.EventListener.create擴展出一個用戶監聽器。
event屬性,定義這個監聽器監聽的類型。
swallowTouches屬性設置是否吃掉事件,事件被吃掉後不會遞給下一層監聽器。
onTouchBegan方法處理觸摸點擊按下事件,咱們在這裏能夠獲取到觸摸點的座標pos。event.getCurrentTarget()獲取當前事件的接受者,並判斷當前的是否點擊到了SushiSprite。
在touch事件中,咱們還能夠添加onTouchMoved/onTouchEnded方法監聽touch移動和結束的回調。若是onTouchBegan返回false後onTouchMoved/onTouchEnded不會執行。
tip: 在onTouchBegan方法中獲取點擊點的座標pos,而後經過cc.rectContainsPoint(target.getBoundingBox(),pos)判斷點擊的點是否在SushiSprite上。
博客文章地址:http://joebon.cc/cocos2d-event-dispatcher