Cocos2d-X 3.0 事件分發機制

這兩天在使用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 值來決定事件相應的優先級,值越小優先級越高

總結一下:

  1. 經過點擊位置進行點擊範圍判斷,來肯定執行哪個sprite的事件監聽器

  2. 若是該位置存在重疊的sprite綁定了相同的事件,則依據優先級(SceneGraphPriority顯示優先級或FixedPriority固定優先級)來順序執行函數回調

  3. 經過設置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);
});

上面的代碼:

  1. 首先經過使用cc.EventListener.create建立了一個Touch事件監聽器touchListener

  2. 而後,經過cc.eventManager.addListener註冊監聽器到事件管理器。cc.EventListener.create擴展出一個用戶監聽器。

  3. event屬性,定義這個監聽器監聽的類型。

  4. swallowTouches屬性設置是否吃掉事件,事件被吃掉後不會遞給下一層監聽器。

  5. onTouchBegan方法處理觸摸點擊按下事件,咱們在這裏能夠獲取到觸摸點的座標pos。event.getCurrentTarget()獲取當前事件的接受者,並判斷當前的是否點擊到了SushiSprite。

  6. 在touch事件中,咱們還能夠添加onTouchMoved/onTouchEnded方法監聽touch移動和結束的回調。若是onTouchBegan返回false後onTouchMoved/onTouchEnded不會執行。

tip: 在onTouchBegan方法中獲取點擊點的座標pos,而後經過cc.rectContainsPoint(target.getBoundingBox(),pos)判斷點擊的點是否在SushiSprite上。

博客文章地址:http://joebon.cc/cocos2d-event-dispatcher

參考文獻

[1] http://cn.cocos2d-x.org/article/index?type=cocos2d-x&url=/doc/cocos-docs-master/manual/framework/cocos2d-js/3-jumping-into-cocos2d-js/3-6-creating-user-interaction-with-event-manager/zh.md

[2] http://cn.cocos2d-x.org/article/index?type=wiki&url=/doc/cocos-docs-master/manual/framework/native/wiki/eventdispatcher-mechanism/zh.md

相關文章
相關標籤/搜索