迄今為止,發現cocos2d-x 3.0最讓人驚艷的地方就是更改了點擊事件機制。(ps:迄今只看了點擊事件這塊,捂嘴笑~~~)
cocos2d-x 2.0 只有CCLayer有點擊事件處理,需要注冊,需要實現onTouchBegan等方法,最坑爹的就是按照優先級來傳遞點擊事件,讓人詬病不已。每次遇到由於優先級而造成的點擊bug,都有一種崩潰之感。
讓人高興的是,從現在開始,這種情況應該就會很少遇到了。閑話不說,開始正文。
3.0版本中,處理點擊事件有兩種方式:
1、函數回調
1 // a selector callback 2 void menuCloseCallback(Object* pSender); 3 4 auto closeItem = MenuItemImage::create("CloseNormal.png","CloseSelected.png", 5 CC_CALLBACK_1(HelloWorld::menuCloseCallback, this)); 6 7 void HelloWorld::menuCloseCallback(Object* pSender) 8 { 9 Director::getInstance()->end(); 10 11 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) 12 exit(0); 13 #endif 14 }
其中CC_CALLBACK_1宏是將函數與對象綁定在一起,1表示這個函數有一個參數。當點擊這個按鈕時,會調用這個回調函數。
除了基於c++11的這個形式的改變,使用方法與先前相同。
2、Listener消息響應方式
Listener的加入,使得Sprite可以很方便的就可以擁有處理點擊事件的能力。再也不用為了寫個能夠響應事件的Sprite而讓去繼承Layer了。總覺得class TestSprite : public CCLayer這種定義Sprite的方式是坑人的一種做法。終於可以將其摒棄了。
3.0版本,只需要為Sprite創建一個Listener,然后將Listener與Sprite綁定,並添加到Listener隊列內即可,方便至極。
另,每一個Listener也只能和一個Sprite進行綁定,而Listener的clone方法,可以很方便的將listener復制為其他對象可用的listener。
廢話少說,上代碼最重要:
1 #ifndef __Touchable_Sprite_Test_H__ 2 #define __Touchable_Sprite_Test_H__ 3 4 #include "cocos2d.h" 5 USING_NS_CC; 6 7 class TouchableSpriteTest : public Layer 8 { 9 public: 10 CREATE_FUNC(TouchableSpriteTest); 11 virtual void onEnter() override; 12 virtual void onExit() override; 13 }; 14 15 #endif
1 #include "TouchableSpriteTest.h" 2 3 void TouchableSpriteTest::onEnter() 4 { 5 Layer::onEnter(); 6 Point origin = Director::getInstance()->getVisibleOrigin(); 7 Size size = Director::getInstance()->getVisibleSize(); 8 9 auto containerForSprite1 = Node::create(); 10 this->addChild(containerForSprite1, 10); 11 auto sprite1 = Sprite::create( "images/CyanSquare.png" ); 12 sprite1->setPosition( origin + Point( size.width * 0.5, size.height * 0.5) + Point( -80, 80 ) ); 13 containerForSprite1->addChild(sprite1); 14 15 auto sprite2 = Sprite::create("images/MagentaSquare.png"); 16 sprite2->setPosition(origin+Point(size.width/2, size.height/2)); 17 addChild(sprite2, 20); 18 19 auto sprite3 = Sprite::create("images/YellowSquare.png"); 20 sprite3->setPosition(Point(0, 0)); 21 sprite2->addChild(sprite3, 1); 22 // Make sprite1 touchable 23 auto listener1 = EventListenerTouchOneByOne::create(); 24 25 listener1->setSwallowTouches(true); 26 27 listener1->onTouchBegan = [](Touch* touch, Event* event){ 28 auto target = static_cast<Sprite*>(event->getCurrentTarget()); 29 30 Point locationInNode = target->convertToNodeSpace(touch->getLocation()); 31 Size s = target->getContentSize(); 32 Rect rect = Rect(0, 0, s.width, s.height); 33 34 if (rect.containsPoint(locationInNode)) 35 { 36 log("sprite began... x = %f, y = %f", locationInNode.x, locationInNode.y); 37 target->setOpacity(180); 38 return true; 39 } 40 return false; 41 }; 42 43 listener1->onTouchMoved = [](Touch* touch, Event* event){ 44 auto target = static_cast<Sprite*>(event->getCurrentTarget()); 45 target->setPosition(target->getPosition() + touch->getDelta()); 46 }; 47 48 listener1->onTouchEnded = [=](Touch* touch, Event* event){ 49 auto target = static_cast<Sprite*>(event->getCurrentTarget()); 50 log("sprite onTouchesEnded.. "); 51 target->setOpacity(255); 52 if (target == sprite2) 53 { 54 containerForSprite1->setLocalZOrder(100); 55 } 56 else if(target == sprite1) 57 { 58 containerForSprite1->setLocalZOrder(0); 59 } 60 }; 61 62 _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1); 63 _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite2); 64 _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite3); 65 66 Rect s_visibleRect = Director::getInstance()->getOpenGLView()->getVisibleRect(); 67 Point right = Point(s_visibleRect.origin.x+s_visibleRect.size.width, s_visibleRect.origin.y+s_visibleRect.size.height/2); 68 69 auto removeAllTouchItem = MenuItemFont::create("Remove All Touch Listeners ",[&]( Ref* sender ){ 70 auto senderItem = static_cast<MenuItemFont*>(sender); 71 senderItem->setString("Only next item could be clicked "); 72 73 _eventDispatcher->removeEventListenersForType( EventListener::Type::TOUCH_ONE_BY_ONE ); 74 75 auto nextItem = MenuItemFont::create("Next", [&](Ref* sender){ 76 }); 77 78 nextItem->setFontSizeObj(16); 79 nextItem->setPosition(right + Point(-100, -30)); 80 81 auto menu2 = Menu::create(nextItem, NULL); 82 menu2->setPosition(Point(0, 0)); 83 menu2->setAnchorPoint(Point(0, 0)); 84 this->addChild(menu2); 85 }); 86 removeAllTouchItem->setFontSizeObj(16); 87 removeAllTouchItem->setPosition(right + Point(-100, 0)); 88 89 auto menu = Menu::create(removeAllTouchItem, nullptr); 90 menu->setPosition(Point(0, 0)); 91 menu->setAnchorPoint(Point(0, 0)); 92 addChild(menu); 93 } 94 95 void TouchableSpriteTest::onExit() 96 { 97 Layer::onExit(); 98 }
千里之行始於足下,一切才剛剛開始,想要理解cocos2dx 3.0的點擊事件,還是需要深入理解其底層實現的。
大家可以去看 Cocos2d-X3.0 刨根問底(七)----- 事件機制Event源碼分析 這應該是一篇好文。
另,本博文參考自:http://blog.csdn.net/fansongy/article/details/12716671
本博主對一切都將不負任何法律責任。