1. 程式人生 > >cocos2dx 3.0 觸控機制

cocos2dx 3.0 觸控機制

在cocos2dx 3.0版本中,廢棄了以往2.x版本的寫法,我們先來看一下Layer.h中的一段程式碼

/* Callback function should not be deprecated, it will generate lots of warnings.
	Since 'setTouchEnabled' was deprecated, it will make warnings if developer overrides onTouchXXX and invokes setTouchEnabled(true) instead of using EventDispatcher::addEventListenerWithXXX.
    */
	//單點觸控
	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);
	//多點觸控
    virtual void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event);
    virtual void onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event);
    virtual void onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event);
    virtual void onTouchesCancelled(const std::vector<Touch*>&touches, Event *unused_event);

單點觸控:(即只有註冊的Layer才能接收觸控事件)

 onTouchBegan:如果返回true:本層的後續Touch事件可以被觸發,並阻擋向後層傳遞

                                 如果返回false,本層的後續Touch事件不能被觸發,並向後傳遞

簡單點來說,如果

1.Layer 只有一層的情況:

virtual bool onTouchBegan(CCTouch *pTouch, CCEvent *pEvent); a.返回false,則ccTouchMoved(),ccTouchEnded()不會再接收到訊息 b.返回true,則ccTouchMoved(),ccTouchEnded()可以接收到訊息
2.Layer 有多層的情況: virtual bool onTouchBegan(CCTouch *pTouch, CCEvent *pEvent); a.返回false,則本層的onTouchMoved(),onTouchEnded()不會再接收到訊息,但是本層之下的其它層會接收到訊息 b.返回true,則本層的onTouchMoved(),onTouchEnded()可以接收到訊息,但是本層之下的其它層不能再接收到訊息

單點觸控簡單用法:

在Layer中新增如下程式碼,重寫onTouchxxx函式

        auto dispatcher = Director::getInstance()->getEventDispatcher();
	auto listener = EventListenerTouchOneByOne::create();
	listener->onTouchBegan = CC_CALLBACK_2(GameLayer::onTouchBegan,this);
	listener->onTouchMoved = CC_CALLBACK_2(GameLayer::onTouchMoved,this);
	listener->onTouchEnded = CC_CALLBACK_2(GameLayer::onTouchEnded,this);
	listener->setSwallowTouches(true);//不向下傳遞觸控
	dispatcher->addEventListenerWithSceneGraphPriority(listener,this);

 listener->setSwallowTouches(true),不向下觸控,簡單點來說,比如有兩個sprite ,A 和 B,A在上B在下(位置重疊),觸控A的時候,B不會受到影響

listener->setSwallowTouches(false)反之,向下傳遞觸控,觸控A也等於觸摸了B


多點觸控點單用法(多個Layer獲取螢幕事件):

        auto dispatcher = Director::getInstance()->getEventDispatcher();
	auto listener1 = EventListenerTouchAllAtOnce::create();
	listener1->onTouchesBegan = CC_CALLBACK_2(GameLayer::onTouchesBegan,this);
	listener1->onTouchesMoved = CC_CALLBACK_2(GameLayer::onTouchesMoved,this);
	listener1->onTouchesEnded = CC_CALLBACK_2(GameLayer::onTouchesEnded,this);
	dispatcher->addEventListenerWithSceneGraphPriority(listener1,this);

或者setTouchEnabled(true),然後重寫layer的onTouchsxxx函式

關於eventDispatcher:

  • 獲取方法:

  • auto dispatcher = Director::getInstance()->getEventDispatcher();

事件監聽器包含以下幾種:

  • 觸控事件 (EventListenerTouch)
  • 鍵盤響應事件 (EventListenerKeyboard)
  • 加速記錄事件 (EventListenerAcceleration)
  • 滑鼠響應事件 (EventListenerMouse)
  • 自定義事件 (EventListenerCustom)

    以上事件監聽器統一由 _eventDispatcher 來進行管理。

優先權: 1.優先順序越低,越先響應事件 2.如果優先順序相同,則上層的(z軸)先接收觸控事件 有兩種方式將 事件監聽器 listener1 新增到 事件排程器_eventDispatcher 中:
void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
    void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)

程式碼展開一下:
void EventDispatcher::addEventListenerWithSceneGraphPriority(EventListener* listener, Node* node)
{
    CCASSERT(listener && node, "Invalid parameters.");
    CCASSERT(!listener->isRegistered(), "The listener has been registered.");
    
    if (!listener->checkAvailable())
        return;
    
    listener->setSceneGraphPriority(node);
    listener->setFixedPriority(0);
    listener->setRegistered(true);
    
    addEventListener(listener);
}

void EventDispatcher::addEventListenerWithFixedPriority(EventListener* listener, int fixedPriority)
{
    CCASSERT(listener, "Invalid parameters.");
    CCASSERT(!listener->isRegistered(), "The listener has been registered.");
    CCASSERT(fixedPriority != 0, "0 priority is forbidden for fixed priority since it's used for scene graph based priority.");
    
    if (!listener->checkAvailable())
        return;
    
    listener->setSceneGraphPriority(nullptr);
    listener->setFixedPriority(fixedPriority);
    listener->setRegistered(true);
    listener->setPaused(false);

    addEventListener(listener);
}


(1)addEventListenerWithSceneGraphPriority 的事件監聽器優先順序是0,而且在 addEventListenerWithFixedPriority 中的事件監聽器的優先順序不可以設定為 0,因為這個是保留給 SceneGraphPriority 使用的。 (2)另外,有一點非常重要,FixedPriority listener新增完之後需要手動remove,而SceneGraphPriority listener是跟node繫結的,在node的解構函式中會被移除。
移除方法:
dispatcher->removeEventListener(listener);