[cocos2d-x 3.6]如何實現“偵聽觸摸事件和偵聽按鍵事件”,觸摸回調函數分別在什麼情況下執行

在以往的版本中,偵聽觸摸事件是這樣寫代碼的:

class A : public CCLayer
{
    virtual bool init();
    virtual bool onTouchBegan(Touch *touch, Event *unused_event);
    virtual void onTouchMoved(Touch *touch, Event *unused_event);
    virtual void onTouchEnded(Touch *touch, Event *unused_event);
    virtual void onTouchCancelled(Touch *touch, Event *unused_event);
};


bool A::init()
{
    setTouchEnabled(true);
}
bool A::onTouchBegan(Touch *touch, Event *unused_event)
{
    ....
}
void A::onTouchMoved(Touch *touch, Event *unused_event)
{
    ....
}
void A::onTouchEnded(Touch *touch, Event *unused_event)
{
    ....
}
void A::onTouchCancelled(Touch *touch, Event *unused_event)
{
    ....
}


在新版本中,上面這套做法被拋棄了。

在新版本中,有一個進化是,只要是Node的派生類都可以偵聽觸摸事件,也可以偵聽按鍵事件,不再是隻有CCLayer的派生類才能偵聽。

在新版本中,偵聽觸摸事件要這樣寫:(回調函數不再是覆蓋基類的虛函數)

class B : public Node
{
    virtual bool init();
    bool myTouchBegan(Touch *touch, Event *unused_event);
    void myTouchMoved(Touch *touch, Event *unused_event);
    void myTouchEnded(Touch *touch, Event *unused_event);
    void myTouchCancelled(Touch *touch, Event *unused_event);
};
bool B::init()
{
    EventListenerTouchOneByOne* listener = EventListenerTouchOneByOne::create();
    listener->setSwallowTouches(true);
    listener->onTouchBegan = CC_CALLBACK_2(B::myTouchBegan, this);
    listener->onTouchMoved = CC_CALLBACK_2(B::myTouchMoved, this);
    listener->onTouchEnded = CC_CALLBACK_2(B::myTouchEnded, this);
    listener->onTouchCancelled = CC_CALLBACK_2(B::myTouchCancelled, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
bool B::myTouchBegan(Touch *touch, Event *unused_event)
{
    ....
}
void B::myTouchMoved(Touch *touch, Event *unused_event)
{
    ....
}
void B::myTouchEnded(Touch *touch, Event *unused_event)
{
    ....
}
void B::myTouchCancelled(Touch *touch, Event *unused_event)
{
    ....
}

相應的,偵聽按鍵事件也不再是調用 setKeyboardEnabled() 函數了,新的寫法是這樣:

class C : public Node
{
    virtual bool init();
    void myKeyPressed(EventKeyboard::KeyCode keyCode, Event* event);
    void myKeyReleased(EventKeyboard::KeyCode keyCode, Event* event);
};
bool C::init()
{
    EventListenerKeyboard* listener = EventListenerKeyboard::create();
    listener->onKeyPressed = CC_CALLBACK_2(UILayerKeyListener::myKeyPressed, this);
    listener->onKeyReleased = CC_CALLBACK_2(UILayerKeyListener::myKeyReleased, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
}
void C::myKeyPressed(EventKeyboard::KeyCode keyCode, Event* event)
{
    ....
}
void C::myKeyReleased(EventKeyboard::KeyCode keyCode, Event* event)
{
    ....
}

可以看到,新版本中使用了一系列的EventListener的派生類

class CC_DLL EventListenerAcceleration : public EventListener
class CC_DLL EventListenerCustom : public EventListener
class CC_DLL EventListenerFocus : public EventListener
class CC_DLL EventListenerKeyboard : public EventListener
class CC_DLL EventListenerMouse : public EventListener
class CC_DLL EventListenerTouchOneByOne : public EventListener
class CC_DLL EventListenerTouchAllAtOnce : public EventListener

====================================================================================

觸摸回調函數,在什麼情況下會觸發:
ccTouchBegan:觸摸開始,返回true可以使得該觸摸點屬於該函數的目標對象,該點的變化只會影響該目標對象函數調用,不會影響其他對象。

ccTouchMoved:觸摸點移動。

ccTouchEnded:觸摸動作結束。

ccTouchCancelled:系統中斷通知需要取消觸摸事件的時候會調用此函數,這個中斷往往是因爲應用長時間沒有響應或者當前視圖從系統的頂層上移除了。

注意1,在ccTouchBegan返回時返回true,可以讓這個觸點屬於這個函數的所屬對象,並且其他對象不再接收該觸點,這樣之後再獲得的觸摸點肯定是它自己。這樣就省去了你對多點觸控時的判斷。


注意2,有很多人認爲手指移出屏幕或者目標對象的範圍就會觸發ccTouchCancelled,但是這種情況下調用的依然是ccTouchEnded函數。事實上,系統中斷通知需要取消觸摸事件的時候會調用ccTouchCancelled,這個中斷被調用往往是因爲出現如下幾種情況:
  a、應用長時間沒有響應或者當前視圖從系統的頂層上移除。
  b、程序進入後臺時,有可能是來點中斷、電量低中斷和部分機型上的Home鍵被按下。
  c、屏幕關閉和觸摸的時候,某種原因導致距離傳感器工作,比如:臉靠近。
  d、部分觸摸權限覆蓋了本應用的觸摸權限。

注意3,觸摸的優先級決定了觸摸的分發順序。觸摸分發只和佈景層的觸摸優先級有關,和佈景層的渲染順序(zOrder)完全沒有關係。哪怕是同樣的觸摸的優先級,也有可能底下一層先收到觸摸,上面那層才接收到。所以處理不同層之間的觸摸關係時,必須通過確定觸摸優先級來實現這些層之間觸摸點的處理順序。優先級相同時數組裏是亂序的,非插入順序。


注意4,“吞噬”觸摸點,如果在本佈景層吞噬掉相應的觸摸點,那麼比它權限低的全都收不到觸摸分發。







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章