cocos2dx有一個編輯器:cocostudio,目前來說,已經是比較好用了,只要加載導出的資源,就可以用上了。省去手動搭建面的麻煩。但是,很多需要事件的地方,操作比較麻煩,所以這里提供一個事件管理器來集中和簡化管理事件。對于C++事件委托方面,我這里使用了是FastDelegate(注:一個牛人寫的)。下面是具體實現的代理,不多。
/*
UI觸摸事件管理器。
原有cocos2dx帶的觸摸事件,每次監聽要操作的步驟比較多,為此增加了一個事件管理器,來集中和簡化管理
*/
#ifndef _X_TOUCH_EVENT_MANAGER_H_
#define _X_TOUCH_EVENT_MANAGER_H_
#include <cocos2d.h>
#include <cocos-ext.h>
#include <FastDelegate.h>
#include <xmap.h>
#include <xlog.h>
namespace zdh
{
USING_NS_CC;
USING_NS_CC_EXT;
class XTouchEventManager : public CCObject
{
public:
//綁定的事件定義
typedef fastdelegate::FastDelegate<void(gui::Widget *, gui::TouchEventType)> TTouchEvent;
typedef int TagID_t;
//一個Tag的觸模事件結構,包括了四個事件
struct STagEvent
{
TTouchEvent EventBegin;
TTouchEvent EventMoved;
TTouchEvent EventEnded;
TTouchEvent EventCanceled;
TTouchEvent * getByType(gui::TouchEventType paramType)
{
switch (paramType)
{
case gui::TOUCH_EVENT_BEGAN:
return &EventBegin;
case gui::TOUCH_EVENT_MOVED:
return &EventMoved;
case gui::TOUCH_EVENT_ENDED:
return &EventEnded;
case gui::TOUCH_EVENT_CANCELED:
return &EventCanceled;
}
return nullptr;
}
//判斷事件是不是都是為空
bool isAllEmpty() const
{
return EventBegin.empty()
&& EventEnded.empty()
&& EventMoved.empty()
&& EventCanceled.empty();
}
};
//Tag事件映射表,可以換用std::map
typedef XMap<TagID_t, STagEvent> TEventMap;
public:
XTouchEventManager()
:m_UI(nullptr)
{}
static XTouchEventManager * create()
{
XTouchEventManager * pRet = new XTouchEventManager();
pRet->autorelease();
return pRet;
}
//property
void setUI(gui::TouchGroup * paramUI)
{
m_UI = paramUI;
}
gui::TouchGroup * getUI()
{
return m_UI;
}
//綁定一個指定Tag和事件類型的事件
TTouchEvent * Bind(TagID_t paramTagID, gui::TouchEventType paramType)
{
if (!(paramType == gui::TOUCH_EVENT_BEGAN
|| paramType == gui::TOUCH_EVENT_CANCELED
|| paramType == gui::TOUCH_EVENT_ENDED
|| paramType == gui::TOUCH_EVENT_MOVED)) return nullptr;
int iIndex = m_Map.getIndexBykey(paramTagID);
if (m_Map.isValidIndex(iIndex))
{
return m_Map.getValue(iIndex).getByType(paramType);
}
else
{
gui::Widget * pWidget = GetNodeByTag(paramTagID);
if (isNULL(pWidget)) return nullptr;
pWidget->addTouchEventListener(this, gui::SEL_TouchEvent(&XTouchEventManager::OnUITouch));
return m_Map[paramTagID].getByType(paramType);
}
}
//移除指定Tag和事件類型的偵聽
void RemoveListen(TagID_t paramTagID, gui::TouchEventType paramType)
{
if (!(paramType == gui::TOUCH_EVENT_BEGAN
|| paramType == gui::TOUCH_EVENT_CANCELED
|| paramType == gui::TOUCH_EVENT_ENDED
|| paramType == gui::TOUCH_EVENT_MOVED)) return;
int iIndex = m_Map.getIndexBykey(paramTagID);
if (m_Map.isValidIndex(iIndex))
{
auto pV = m_Map.getValue(iIndex);
pV.getByType(paramType)->clear();
if (pV.isAllEmpty()) //如果這個Tag完全沒有事件偵聽,那么就清除這個Tag的偵聽
{
RemoveListen(paramTagID);
}
}
}
//移除指定Tag的偵聽
void RemoveListen(TagID_t paramTagID)
{
gui::Widget * pWidget = GetNodeByTag(paramTagID);
if (isNotNULL(pWidget))
{
pWidget->addTouchEventListener(nullptr, nullptr);
}
m_Map.RemoveByKey(paramTagID);
}
private:
//當UI被偵聽的事件,被觸發
void OnUITouch(CCObject* paramSender, gui::TouchEventType paramType)
{
gui::Widget * pUIControl = dynamic_cast<gui::Widget *>(paramSender);
if (isNULL(pUIControl)) return;
TagID_t tagID = pUIControl->getTag();
STREAM_INFO << "Sender Tag=" << tagID << ", paramType=" << paramType;
int iIndex = m_Map.getIndexBykey(tagID);
if (m_Map.isValidIndex(iIndex))
{
auto pV = m_Map.getValue(iIndex);
auto pEvent = pV.getByType(paramType);
if (isNotNULL(pEvent) && (!pEvent->empty()))
{
(*pEvent)(pUIControl, paramType); //調用事件
}
}
}
//取UI中指定Tag的widget對象
gui::Widget * GetNodeByTag(TagID_t paramTag)
{
if (isNULL(m_UI)) return nullptr;
return m_UI->getWidgetByTag(paramTag);
}
private:
gui::TouchGroup * m_UI; //用Cocostudio UI編輯器,然后導入生成的UI對象
TEventMap m_Map; //事件偵聽映射表
};
}
#endif
使用例子:在Init函數
m_EventManager = XTouchEventManager::create();
m_EventManager->retain();
gui::TouchGroup* ul = gui::TouchGroup::create();
ul->addWidget(GUIReader::shareReader()->widgetFromJsonFile("MainUI_1.ExportJson"));
this->addChild(ul, 2);
m_EventManager->setUI(m_MainUI);
最后,事件綁定:
m_EventManager->Bind(ET_BUTTON_EXIT, gui::TOUCH_EVENT_ENDED)->bind(this, &XSceneMain::OnExit);
m_EventManager->Bind(ET_BUTTON_SAVE, gui::TOUCH_EVENT_ENDED)->bind(this, &XSceneMain::OnSave);
事件的定義:
void XSceneMain::OnExit(gui::Widget * paramSender, gui::TouchEventType paramType)
{
STREAM_INFO << "OnExit";
}
void XSceneMain::OnSave(gui::Widget * paramSender, gui::TouchEventType paramType)
{
STREAM_INFO << "OnSave";
}
依賴的代碼參考:我的開發代碼