1. 程式人生 > >關於cocos2d-x 3.0的點擊交互處理

關於cocos2d-x 3.0的點擊交互處理

clipboard 3.0 static php 此外 eas -h con spl

轉自:http://blog.csdn.net/fansongy/article/details/12716671

1、概述


遊戲也好,程序也好,僅僅有能與用戶交互才有意義。手機上的交互大致能夠分為兩部分:點擊和輸入。當中點擊更為重要,差點兒是遊戲中所有的交互。在Cocos2d-x 3.0中。更改了dispatch機制。同一時候增加了兩種新的交互形式:listener 和touchEvent回調。

加上先前版本號中的點擊函數回調,與重寫layer層的touch消息響應,構成了一個相對完整的交互模式。

先上一張Demo的圖:
技術分享


2、四種點擊


1、函數回調

函數回調是最簡單的響應形式。一直以來被用於MenuItem中的點擊處理。

在新版本號中,此處發生了些小改變。我們能夠看到在生成的程序中相關代碼是這種:

[cpp] view plaincopyprint?

  1. // a selector callback
  2. void menuCloseCallback(Object* pSender);
  3. auto closeItem = MenuItemImage::create("CloseNormal.png","CloseSelected.png"
    ,
  4. CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
  5. void HelloWorld::menuCloseCallback(Object* pSender)
  6. {
  7. Director::getInstance()->end();
  8. #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
  9. exit(0);
  10. #endif
  11. }

當中CC_CALLBACK_1宏是將函數與對象綁定在一起,1表示這個函數有一個參數。當點擊這個button時,會調用這個回調函數。

除了基於c++11的這個形式的改變,用法與先前同樣。


此種方式已經被舍棄,能夠使用第四種方法做替代。

2、Layer的touch消息響應

盡管重寫了底層的dispatch,但對這層的使用影響並不大。

我們相同須要重寫:

[cpp] view plaincopyprint

" style="color:rgb(160,160,160); text-decoration:none; border:none; padding:0px; margin:0px 10px 0px 0px; background-color:inherit">?

  1. //單點響應
  2. virtual bool onTouchBegan(Touch* touch, Event *event) override;
  3. virtual void onTouchMoved(Touch* touch, Event *event) override;
  4. virtual void onTouchEnded(Touch* touch, Event *event) override;
  5. virtual void onTouchCancelled(Touch *touch, Event *event) override;
  6. //多點響應
  7. virtual void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event);
  8. virtual void onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event);
  9. virtual void onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event);
  10. virtual void onTouchesCancelled(const std::vector<Touch*>& touches, Event *unused_event);


重寫這些函數來對layer的點擊做處理。當然。我們須要:

[cpp] view plaincopyprint?
  1. setTouchEnabled(true)。

此外有個小修改。對於單點觸控響應,能夠調用:

[cpp] view plaincopyprint?
  1. //設置為單點響應
  2. setTouchMode(Touch::DispatchMode::ONE_BY_ONE);
  3. //設置為多點響應(默認)
  4. setTouchMode(Touch::DispatchMode::ALL_AT_ONCE);

進行設置,而不須要再用設置Delegate的方式來做了。


3、TouchEvent響應

這是新增加的響應方式。它主要是使用在UIWidget上的。能夠將其看做是函數回調的一個擴展。為很多其它的響應處理提供可能。用法大致是:
[cpp] view plaincopyprint?

  1. //聲明
  2. void touchButton(Object* object,TouchEventType type);
  3. //掛接到控件上
  4. uiButton->addTouchEventListener(this,toucheventselector(HelloWorld::touchButton));
  5. //實現
  6. void HelloWorld::touchButton(Object* object,TouchEventType type)
  7. {
  8. LabelTTF* label;
  9. switch (type)
  10. {
  11. case TouchEventType::TOUCH_EVENT_BEGAN:
  12. label = static_cast<LabelTTF*>(getChildByTag(11));
  13. label->setString("按下button");
  14. break;
  15. case TouchEventType::TOUCH_EVENT_MOVED:
  16. label = static_cast<LabelTTF*>(getChildByTag(11));
  17. label->setString("按下button移動");
  18. break;
  19. case TouchEventType::TOUCH_EVENT_ENDED:
  20. label = static_cast<LabelTTF*>(getChildByTag(11));
  21. label->setString("放開button");
  22. break;
  23. case TouchEventType::TOUCH_EVENT_CANCELED:
  24. label = static_cast<LabelTTF*>(getChildByTag(11));
  25. label->setString("取消點擊");
  26. break;
  27. default:
  28. break;
  29. }
  30. }

由於全部的UIWidget都要加入到UILayer上。而UILayer通常作為UI的Widget都會在最上層,所以能夠“基本上”覺得這樣的使用方式會優先於其它方式處理點擊消息。由於UILayer也會有層級的改變,比方它和MenuItem之間的關系。所以說“基本上”。


4、Listener消息響應方式

這樣的實現也是新增加的。它更像是點擊的一個層次過濾器。點擊時,在listener隊裏中進行過濾。每個listener檢查自己保存的touch消息響應是否會被觸發。

一層一層過濾,最後在到Layer的touch消息響應。

我認為它的設計的初衷是為隨意sprite提供一套自己制定的點擊響應。但這種實現仍然要寫非常多條件推斷。沒有可以控件化。可能我的理解有些偏差,歡迎討論。

它被設計成一個全局點擊響應控制。詳細的使用方法大致是這樣:


[cpp] view plaincopyprint?
  1. //auto dispatcher = EventDispatcher::getInstance();
  2. // auto myListener = EventListenerTouch::create(Touch::DispatchMode::ONE_BY_ONE);
  3. auto dispatcher = Director::getInstance()->getEventDispatcher();
  4. auto myListener = EventListenerTouchOneByOne::create();
  5. //假設不增加此句消息依然會向下傳遞
  6. myListener->setSwallowTouches(true);
  7. myListener->onTouchBegan = [=](Touch* touch,Event* event)
  8. {
  9. //some check
  10. if (pass)
  11. {
  12. return true;
  13. }
  14. return false;
  15. };
  16. myListener->onTouchMoved = [=](Touch* touch,Event* event)
  17. {
  18. //do something
  19. };
  20. myListener->onTouchEnded = [=](Touch* touch,Event* event)
  21. {
  22. //do something
  23. };
  24. dispatcher->addEventListenerWithSceneGraphPriority(myListener,mySprite1);
  25. dispatcher->addEventListenerWithSceneGraphPriority(myListener,mySprite2);
在這裏相同會用到CC_CALLBACK_x函數。

其原理是在dispatcher中檢查listener列表,比如myListener或加進來的其它listener。然後每一個listener檢查自己中的Item看是否能達到檢查條件,比如:mySprite1,mySprite2。

然後運行對應的操作。但這種話,當控件非常多的時候,每一次事件都進行這種雙鏈表的檢查操作不知會不會影響些性能?


3、實例

光說不練假把式,於是就動手寫了一個上面的Demo:

點擊背景區域能夠移動整個場景。點擊藍色小方塊能夠半透明移動它,點擊藍色button能夠更改文字。顯示狀態。點擊右下角button退出程序。

項目配置可參照:

Cocos2d-x 3.0 開發(十六)cocos2dx-3.0beta版建立新項目並載入CocoStudio導出文件

4、總結

依據不同的交互須要。選擇不同的實現方式,會更有利於我們的維護和擴展,對應樣例能夠在以下下載。


Demo下載:http://download.csdn.net/detail/fansongy/6399291 不要資源分,認為好勞煩點下 “頂” ~

Demo For Beta2 下載:http://download.csdn.net/detail/fansongy/6892047


關於cocos2d-x 3.0的點擊交互處理