1. 程式人生 > >Cocos2d-x 3.0開發(三)點選互動的四種處理

Cocos2d-x 3.0開發(三)點選互動的四種處理

1、概述

    遊戲也好,程式也好,只有能與使用者互動才有意義。手機上的互動大致可以分為兩部分:點選和輸入。其中點選更為重要,幾乎是遊戲中全部的互動。在Cocos2d-x 3.0中,更改了dispatch機制。同時加入了兩種新的互動形式:listener 和touchEvent回撥。加上先前版本中的點選函式回撥,與重寫layer層的touch訊息響應,構成了一個相對完整的互動模式。先上一張Demo的圖:

2、四種點選

1、函式回撥

函式回撥是最簡單的響應形式,一直以來被用於MenuItem中的點選處理。在新版本中,此處發生了些小改變。我們可以看到在生成的程式中相關程式碼是這樣的:
// a selector callback
void menuCloseCallback(Object* pSender);

auto closeItem = MenuItemImage::create("CloseNormal.png","CloseSelected.png",
                        CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));

void HelloWorld::menuCloseCallback(Object* pSender)
{
    Director::getInstance()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

    其中CC_CALLBACK_1巨集是將函式與物件繫結在一起,1表示這個函式有一個引數。當點選這個按鈕時,會呼叫這個回撥函式。

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

此種方式已經被捨棄,可以使用第四種方法做替代。

   2、Layer的touch訊息響應

    雖然重寫了底層的dispatch,但對這層的使用影響並不大。我們同樣需要重寫:

//單點響應
virtual bool onTouchBegan(Touch* touch, Event  *event) override;
virtual void onTouchMoved(Touch* touch, Event  *event) override;
virtual void onTouchEnded(Touch* touch, Event  *event) override;
virtual void onTouchCancelled(Touch *touch, Event *event) override;

//多點響應
virtual bool onTouchesBegan(Touch* touch, Event  *event) override;
virtual void onTouchesMoved(Touch* touch, Event  *event) override;
virtual void onTouchesEnded(Touch* touch, Event  *event) override;
virtual void onTouchesCancelled(Touch *touch, Event *event) override;

    重寫這些函式來對layer的點選做處理。當然,我們需要:

setTouchEnabled(true)。

   此外有個小改動。對於單點觸控響應,可以呼叫:

//設定為單點響應
setTouchMode(Touch::DispatchMode::ONE_BY_ONE);
//設定為多點響應(預設)
setTouchMode(Touch::DispatchMode::ALL_AT_ONCE);


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

    3、TouchEvent響應

    這是新加入的響應方式。它主要是使用在UIWidget上的。可以將其看做是函式回撥的一個擴充套件,為更多的響應處理提供可能。使用方法大致是:
//宣告
void touchButton(Object* object,TouchEventType type);

//掛接到控制元件上
uiButton->addTouchEventListener(this,toucheventselector(HelloWorld::touchButton));

//實現
void HelloWorld::touchButton(Object* object,TouchEventType type)
{
	LabelTTF* label;
	switch (type)
	{
	case TouchEventType::TOUCH_EVENT_BEGAN:
		label = static_cast<LabelTTF*>(getChildByTag(11));
		label->setString("按下按鈕");
		break;
	case TouchEventType::TOUCH_EVENT_MOVED:
		label = static_cast<LabelTTF*>(getChildByTag(11));
		label->setString("按下按鈕移動");
		break;
	case TouchEventType::TOUCH_EVENT_ENDED:
		label = static_cast<LabelTTF*>(getChildByTag(11));
		label->setString("放開按鈕");
		break;
	case TouchEventType::TOUCH_EVENT_CANCELED:
		label = static_cast<LabelTTF*>(getChildByTag(11));
		label->setString("取消點選");
		break;
	default:
		break;
	}
}

    因為所有的UIWidget都要新增到UILayer上,而UILayer通常作為UI的Widget都會在最上層,所以可以“基本上”認為這種使用方式會優先於其他方式處理點選訊息。因為UILayer也會有層級的改變,比如它和MenuItem之間的關係。所以說“基本上”。


4、Listener訊息響應方式

    這種實現也是新加入的。它更像是點選的一個層次過濾器。點選時,在listener隊裡中進行過濾。每一個listener檢查自己儲存的touch訊息響應是否會被觸發。一層一層過濾,最後在到Layer的touch訊息響應。

    我覺得它的設計的初衷是為任意sprite提供一套自己制定的點選響應。但這樣的實現仍然要寫很多條件判斷,沒有能夠控制元件化。可能我的理解有些偏差,歡迎討論。

    它被設計成一個全域性點選響應控制。具體的用法大致是這樣:

//auto dispatcher = EventDispatcher::getInstance();
//	auto myListener = EventListenerTouch::create(Touch::DispatchMode::ONE_BY_ONE);
auto dispatcher = Director::getInstance()->getEventDispatcher();
auto myListener = EventListenerTouchOneByOne::create();

//如果不加入此句訊息依舊會向下傳遞
myListener->setSwallowTouches(true);

myListener->onTouchBegan = [=](Touch* touch,Event* event)
{
    //some check
    if (pass)
    {
        return true;
    }
    return false;
};

myListener->onTouchMoved = [=](Touch* touch,Event* event)
{
	//do something
};

myListener->onTouchEnded = [=](Touch* touch,Event* event)
{
	//do something
};

dispatcher->addEventListenerWithSceneGraphPriority(myListener,mySprite1);
dispatcher->addEventListenerWithSceneGraphPriority(myListener,mySprite2);


    其原理是在dispatcher中檢查listener列表,例如myListener或加進來的其他listener。然後每個listener檢查自己中的Item看能否達到檢查條件,例如:mySprite1,mySprite2。然後執行相應的操作。但這樣的話,當控制元件很多的時候,每一次事件都進行這種雙鏈表的檢查操作不知會不會影響些效能?


3、例項

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

    點選背景區域可以移動整個場景,點選藍色小方塊可以半透明移動它,點選藍色按鈕可以更改文字,顯示狀態。點選右下角按鈕退出程式。

    專案配置可參照:

4、總結

    根據不同的互動需要,選擇不同的實現方式,會更有利於我們的維護和擴充套件,相應例子可以在下面下載。

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

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