您的位置:首页 > 移动开发 > Cocos引擎

cocos2d-x触摸事件详细分析

2014-05-25 17:04 309 查看
在cocos2d-x启动时会初始化CCEGLView(不同平台,都有自己的实现,由于自己是在win32平台下开发,所以这里的CCEGLView实现是win32下的)。

int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR    lpCmdLine,
int       nCmdShow)
{
...
CCEGLView* eglView = CCEGLView::sharedOpenGLView();
...
}
然后再初始化导演时会把它设置进去

bool AppDelegate::applicationDidFinishLaunching() {
...
CCDirector* pDirector = CCDirector::sharedDirector();
CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();
...
}
另外在初始化导演时也会做另一件重要的事情——创建触摸分发事件(往下还有键盘和重力感应事件,这里只说触摸事件):

bool CCDirector::init(void)
{
...
m_pTouchDispatcher = new CCTouchDispatcher();
m_pTouchDispatcher->init();
...

return true;
}
这样便完成了游戏的触摸分发的创建。

接下来看什么时候会触发这个事件。

触发时会按以下流程来完成:

1)在创建CCEGLView时会初始化窗口信息,包括事件的处理

CCEGLView* CCEGLView::sharedOpenGLView()
{

if (s_pEglView == NULL)
{
s_pEglView = new CCEGLView();
if(!s_pEglView->Create())//初始化窗口信息
{
delete s_pEglView;
s_pEglView = NULL;
}
}

return s_pEglView;
}
bool CCEGLView::Create()
{
...
wc.lpfnWndProc    = _WindowProc;                    // WndProc Handles Messages
...

return bRet;
}
上面的那个消息便是我们要的内容。

static LRESULT CALLBACK _WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
...
return s_pMainWindow->WindowProc(uMsg, wParam, lParam);
...
}
LRESULT CCEGLView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
BOOL bProcessed = FALSE;

switch (message)
{
case WM_LBUTTONDOWN://鼠标左键按下
#if(_MSC_VER >= 1600)
// Don't process message generated by Windows Touch
if (m_bSupportTouch && (s_pfGetMessageExtraInfoFunction() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) break;
#endif /* #if(_MSC_VER >= 1600) */

if (m_pDelegate && MK_LBUTTON == wParam)
{
POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
CCPoint pt(point.x, point.y);
pt.x /= m_fFrameZoomFactor;
pt.y /= m_fFrameZoomFactor;
CCPoint tmp = ccp(pt.x, m_obScreenSize.height - pt.y);//得到触摸点
if (m_obViewPortRect.equals(CCRectZero) || m_obViewPortRect.containsPoint(tmp))
{
m_bCaptured = true;//只有按下鼠标的左键后后面的事件才会继续被捕捉
SetCapture(m_hWnd);
int id = 0;
handleTouchesBegin(1, &id, &pt.x, &pt.y);//处理CCTouchBegin事件
}
}
break;

case WM_MOUSEMOVE://鼠标左键按下并移动
#if(_MSC_VER >= 1600)
// Don't process message generated by Windows Touch
if (m_bSupportTouch && (s_pfGetMessageExtraInfoFunction() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) break;
#endif /* #if(_MSC_VER >= 1600) */
if (MK_LBUTTON == wParam && m_bCaptured)
{
POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
CCPoint pt(point.x, point.y);
int id = 0;
pt.x /= m_fFrameZoomFactor;
pt.y /= m_fFrameZoomFactor;
handleTouchesMove(1, &id, &pt.x, &pt.y);//处理CCTouchMove事件
}
break;

case WM_LBUTTONUP://鼠标左键抬起
#if(_MSC_VER >= 1600)
// Don't process message generated by Windows Touch
if (m_bSupportTouch && (s_pfGetMessageExtraInfoFunction() & MOUSEEVENTF_FROMTOUCH) == MOUSEEVENTF_FROMTOUCH) break;
#endif /* #if(_MSC_VER >= 1600) */
if (m_bCaptured)
{
POINT point = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
CCPoint pt(point.x, point.y);
int id = 0;
pt.x /= m_fFrameZoomFactor;
pt.y /= m_fFrameZoomFactor;
handleTouchesEnd(1, &id, &pt.x, &pt.y);//处理CCTouchEnd事件

ReleaseCapture();
m_bCaptured = false;//捕捉结束
}
break;
...
//处理其他事件,如键盘,和后续操作
return 0;
}
到这里就很明显的可以看出在win32平台就是用鼠标的左键来模拟触摸的。其中,对应的三个触摸事件的声明和实现被放在它的父类中去实现,也就是CCEGLViewProtocol

class CC_DLL CCEGLView : public CCEGLViewProtocol
因为它与平台无关,即CCEGLview实现不同平台的不同的触摸处理,而CCEGLViewProtocol则定义了这些行为而已,而这些行为统一由cocos2d-x,这样便能大大的降低引擎与平台的耦合度。

综合上面也内容可以看出cocos2d-x在启动时会初始化导演,并设置CCEGLView,而CCEGLiew的父类CCEGLViewProtocol则定义了触摸的行为方法,所以在设置CCEGLView时就已经悄悄的把这些行为与导演绑定在一起了,而且初始化导演时也已经创建了能触摸分发事件的句柄。

bool AppDelegate::applicationDidFinishLaunching() {
...

pDirector->setOpenGLView(pEGLView);

...
}
void CCDirector::setOpenGLView(CCEGLView *pobOpenGLView)
{
...
m_pobOpenGLView->setTouchDelegate(m_pTouchDispatcher);
m_pTouchDispatcher->setDispatchEvents(true);//设置触摸事件为true,这里要一定要设置为true,不然所有事件都失效
...
}
这样在CCEGLViewProtocol中便能用m_pTouchDispatcher来操作触摸分发事件了。

void CCEGLViewProtocol::handleTouchesBegin(int num, int ids[], float xs[], float ys[])
{
//计算触摸点集合set
...

m_pDelegate->touchesBegan(&set, NULL);
}

void CCEGLViewProtocol::handleTouchesMove(int num, int ids[], float xs[], float ys[])
{
//计算触摸点集合set
...

m_pDelegate->touchesMoved(&set, NULL);
}

void CCEGLViewProtocol::handleTouchesEnd(int num, int ids[], float xs[], float ys[])
{
//计算触摸点集合set
...

m_pDelegate->touchesEnded(&set, NULL);
}

void CCEGLViewProtocol::handleTouchesCancel(int num, int ids[], float xs[], float ys[])
{
//计算触摸点集合set
...

m_pDelegate->touchesCancelled(&set, NULL);
}
可以看到这些事件的处理的第二个参数都是NULL,也就是说是个无用参数(之所以这个无用的参数据说是cocos2d-iphone遗留下来的)。

接下来看触摸分发类的对这些方法的定义,这些定义是在它的父类中,即触摸事件委托类EGLTouchDelegate:

class CC_DLL EGLTouchDelegate//触摸事件委托
{
public:
/**
* @lua NA
*/
virtual void touchesBegan(CCSet* touches, CCEvent* pEvent) = 0;//触摸被按下
/**
* @lua NA
*/
virtual void touchesMoved(CCSet* touches, CCEvent* pEvent) = 0;//触摸移动
/**
* @lua NA
*/
virtual void touchesEnded(CCSet* touches, CCEvent* pEvent) = 0;//触摸结束
/**
* @lua NA
*/
virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent) = 0;//当系统被通知需要取消触摸事件才会触发它,一般不用它
/**
* @lua NA
*/
virtual ~EGLTouchDelegate() {}//析构
};


class CC_DLL CCTouchDispatcher : public CCObject, public EGLTouchDelegate
{
public:
/**
* @lua NA
*/
//析构
~CCTouchDispatcher();
/**
* @lua NA
*/
//初始化
bool init(void);
/**
* @lua NA
*/
//构造
CCTouchDispatcher()
: m_pTargetedHandlers(NULL)
, m_pStandardHandlers(NULL)
, m_pHandlersToAdd(NULL)
, m_pHandlersToRemove(NULL)

{}

public:
/** Whether or not the events are going to be dispatched. Default: true */
//是否能触摸分发事件
bool isDispatchEvents(void);
void setDispatchEvents(bool bDispatchEvents);

/** Adds a standard touch delegate to the dispatcher's list.
* See StandardTouchDelegate description.
* IMPORTANT: The delegate will be retained.
* @lua NA
*/
//注册标准触摸事件
void addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority);

/** Adds a targeted touch delegate to the dispatcher's list.
* See TargetedTouchDelegate description.
* IMPORTANT: The delegate will be retained.
* @lua NA
*/
//注册目标触摸事件
void addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches);

/** Removes a touch delegate.
* The delegate will be released
* @lua NA
*/
//移除指定触摸事件
void removeDelegate(CCTouchDelegate *pDelegate);

/** Removes all touch delegates, releasing all the delegates
* @lua NA
*/
//移除所有触摸事件
void removeAllDelegates(void);

/** Changes the priority of a previously added delegate. The lower the number,
* the higher the priority
* @lua NA
*/
//设置触摸优先级
void setPriority(int nPriority, CCTouchDelegate *pDelegate);
/**
* @lua NA
*/
//触摸操作
void touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex);

//重写父类方法
/**
* @lua NA
*/
virtual void touchesBegan(CCSet* touches, CCEvent* pEvent);
/**
* @lua NA
*/
virtual void touchesMoved(CCSet* touches, CCEvent* pEvent);
/**
* @lua NA
*/
virtual void touchesEnded(CCSet* touches, CCEvent* pEvent);
/**
* @lua NA
*/
virtual void touchesCancelled(CCSet* touches, CCEvent* pEvent);

public:
/**
* @lua NA
*/
//触摸句柄,握有触摸的优先级
CCTouchHandler* findHandler(CCTouchDelegate *pDelegate);
protected:
//强制的移除触摸事件
void forceRemoveDelegate(CCTouchDelegate *pDelegate);
//强制的增加触摸句柄
void forceAddHandler(CCTouchHandler *pHandler, CCArray* pArray);
//强制的移除所有触摸事件
void forceRemoveAllDelegates(void);
//按优先级排序数组
void rearrangeHandlers(CCArray* pArray);
//查找指定的触摸句柄,没有查找到,则返回空
CCTouchHandler* findHandler(CCArray* pArray, CCTouchDelegate *pDelegate);

protected:
CCArray* m_pTargetedHandlers;//存储目标触摸事件的数组
CCArray* m_pStandardHandlers;//存储标准触摸事件的数组

bool m_bLocked;//锁定触摸操作
bool m_bToAdd;//是否有触摸事件待分发
bool m_bToRemove;//是否有触摸事件待移除
CCArray* m_pHandlersToAdd;//存储待分发触摸事件的缓冲数组
struct _ccCArray *m_pHandlersToRemove;//存储待移除触摸事件的缓冲数组
bool m_bToQuit;//是否取消当前的触摸分发
bool m_bDispatchEvents;//是否分发事件,false不分发

// 4, 1 for each type of event
struct ccTouchHandlerHelperData m_sHandlerHelperData[ccTouchMax];//操作类别,辅助用
};


在cocos2d-x中,有两种触摸事件类型,分别是标准触摸事件和带目标触摸事件,这个两个事件在分发是分别存在各自的触摸句柄类的数组中。

触摸句柄:
//触摸事件句柄
class CC_DLL  CCTouchHandler : public CCObject
{
public:
virtual ~CCTouchHandler(void);//析构

/** delegate */
CCTouchDelegate* getDelegate();//获取触摸事件委托
void setDelegate(CCTouchDelegate *pDelegate);//设置触摸事件委托

/** priority */
int getPriority(void);//获取优先级
void setPriority(int nPriority);//设置优先级

/** enabled selectors */
//不知何用???
int getEnabledSelectors(void);
void setEnalbedSelectors(int nValue);

/** initializes a TouchHandler with a delegate and a priority */
virtual bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority);//初始化

public:
/** allocates a TouchHandler with a delegate and a priority */
static CCTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority);//创建触摸句柄类

protected:
CCTouchDelegate *m_pDelegate;//触摸事件委托
int m_nPriority;//优先级
int m_nEnabledSelectors;//不知何用???
};

//标准触摸事件句柄
class CC_DLL  CCStandardTouchHandler : public CCTouchHandler
{
public:
/** initializes a TouchHandler with a delegate and a priority */
virtual bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority);//初始化

public:
/** allocates a TouchHandler with a delegate and a priority */
static CCStandardTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority);//创建标准触摸句柄类
};

//目标触摸事件句柄
class CC_DLL  CCTargetedTouchHandler : public CCTouchHandler
{
public:
~CCTargetedTouchHandler(void);

/** whether or not the touches are swallowed */
bool isSwallowsTouches(void);//获取是否吞噬分发
void setSwallowsTouches(bool bSwallowsTouches);//设置是否吞噬分发

/** MutableSet that contains the claimed touches */
CCSet* getClaimedTouches(void);//存储用于声明的触摸事件

/** initializes a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */
bool initWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow);//初始化

public:
/** allocates a TargetedTouchHandler with a delegate, a priority and whether or not it swallows touches or not */
static CCTargetedTouchHandler* handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow);//创建目标触摸句柄类

protected:
bool m_bSwallowsTouches;
CCSet *m_pClaimedTouches;
};


CCTouchDelegate* CCTouchHandler::getDelegate(void)
{
return m_pDelegate;//返回触摸委托
}

void CCTouchHandler::setDelegate(CCTouchDelegate *pDelegate)
{
if (pDelegate)//传进来的委托不为空
{
dynamic_cast<CCObject*>(pDelegate)->retain();//引用计数加1
}

if (m_pDelegate)//如果之前设置过委托,释放掉它
{
dynamic_cast<CCObject*>(m_pDelegate)->release();
}

m_pDelegate = pDelegate;//设置新的委托
}

int CCTouchHandler::getPriority(void)
{
return m_nPriority;//返回优先级
}

void CCTouchHandler::setPriority(int nPriority)
{
m_nPriority = nPriority;//设置优先级
}

int CCTouchHandler::getEnabledSelectors(void)
{
return m_nEnabledSelectors;
}

void CCTouchHandler::setEnalbedSelectors(int nValue)
{
m_nEnabledSelectors = nValue;
}

CCTouchHandler* CCTouchHandler::handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority)
{
CCTouchHandler *pHandler = new CCTouchHandler();//创建新的触摸句柄

if (pHandler)
{
if (pHandler->initWithDelegate(pDelegate, nPriority))//初始化
{
pHandler->autorelease();//放入内存回收池
}
else
{
CC_SAFE_RELEASE_NULL(pHandler);
}
}

return pHandler;
}

bool CCTouchHandler::initWithDelegate(CCTouchDelegate *pDelegate, int nPriority)
{
CCAssert(pDelegate != NULL, "touch delegate should not be null");

m_pDelegate = pDelegate; //设置委托

dynamic_cast<CCObject*>(pDelegate)->retain();//引用计数加1

m_nPriority = nPriority;//设置优先级
m_nEnabledSelectors = 0;

return true;
}

CCTouchHandler::~CCTouchHandler(void)
{
if (m_pDelegate)//释放掉触摸委托资源
{
dynamic_cast<CCObject*>(m_pDelegate)->release();
}
}

// implementation of CCStandardTouchHandler
bool CCStandardTouchHandler::initWithDelegate(CCTouchDelegate *pDelegate, int nPriority)
{
if (CCTouchHandler::initWithDelegate(pDelegate, nPriority))//初始化
{
return true;
}

return false;
}

CCStandardTouchHandler* CCStandardTouchHandler::handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority)
{
CCStandardTouchHandler* pHandler = new CCStandardTouchHandler();

if (pHandler)
{
if (pHandler->initWithDelegate(pDelegate, nPriority))//初始化
{
pHandler->autorelease();//放入内存回收池
}
else
{
CC_SAFE_RELEASE_NULL(pHandler);
}
}

return pHandler;
}

// implementation of CCTargetedTouchHandler

bool CCTargetedTouchHandler::isSwallowsTouches(void)
{
return m_bSwallowsTouches;//返回是否吞噬事件
}

void CCTargetedTouchHandler::setSwallowsTouches(bool bSwallowsTouches)
{
m_bSwallowsTouches = bSwallowsTouches;//设置是否吞噬事件
}

CCSet* CCTargetedTouchHandler::getClaimedTouches(void)
{
return m_pClaimedTouches;//返回声明触摸事件容器
}

CCTargetedTouchHandler* CCTargetedTouchHandler::handlerWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow)
{
CCTargetedTouchHandler *pHandler = new CCTargetedTouchHandler();
if (pHandler)
{
if (pHandler->initWithDelegate(pDelegate, nPriority, bSwallow))//初始化
{
pHandler->autorelease();//放入内存回收池
}
else
{
CC_SAFE_RELEASE_NULL(pHandler);
}
}

return pHandler;
}

bool CCTargetedTouchHandler::initWithDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallow)
{
if (CCTouchHandler::initWithDelegate(pDelegate, nPriority))//初始化
{
m_pClaimedTouches = new CCSet();
m_bSwallowsTouches = bSwallow;

return true;
}

return false;
}

CCTargetedTouchHandler::~CCTargetedTouchHandler(void)
{
CC_SAFE_RELEASE(m_pClaimedTouches);//释放资源
}
最后便是触摸分发事件的实现了:

static int less(const CCObject* p1, const CCObject* p2)
{
return ((CCTouchHandler*)p1)->getPriority() < ((CCTouchHandler*)p2)->getPriority();//判断两个参数间的优先级大小,排序用
}

bool CCTouchDispatcher::isDispatchEvents(void)
{
return m_bDispatchEvents;//返回触摸事件是否分发
}

void CCTouchDispatcher::setDispatchEvents(bool bDispatchEvents)
{
m_bDispatchEvents = bDispatchEvents;//设置触摸事件是否分发
}

/*
+(id) allocWithZone:(CCZone *)zone
{
@synchronized(self) {
CCAssert(sharedDispatcher == nil, @"Attempted to allocate a second instance of a singleton.");
return [super allocWithZone:zone];
}
return nil; // on subsequent allocation attempts return nil
}
*/

bool CCTouchDispatcher::init(void)
{
m_bDispatchEvents = true;//默认情况下设置触摸事件分发
//初始化目标触摸事件的容器
m_pTargetedHandlers = CCArray::createWithCapacity(8);
m_pTargetedHandlers->retain();
//初始化标准触摸事件的容器
m_pStandardHandlers = CCArray::createWithCapacity(4);
m_pStandardHandlers->retain();
//初始化待分发触摸事件的缓冲容器
m_pHandlersToAdd = CCArray::createWithCapacity(8);
m_pHandlersToAdd->retain();
//初始化待移除触摸事件的缓冲容器
m_pHandlersToRemove = ccCArrayNew(8);

//初始化其他属性
m_bToRemove = false;
m_bToAdd = false;
m_bToQuit = false;
m_bLocked = false;
//初始化触摸操作类型
m_sHandlerHelperData[CCTOUCHBEGAN].m_type = CCTOUCHBEGAN;
m_sHandlerHelperData[CCTOUCHMOVED].m_type = CCTOUCHMOVED;
m_sHandlerHelperData[CCTOUCHENDED].m_type = CCTOUCHENDED;
m_sHandlerHelperData[CCTOUCHCANCELLED].m_type = CCTOUCHCANCELLED;

return true;
}

CCTouchDispatcher::~CCTouchDispatcher(void)
{
//释放所用的容器的资源
CC_SAFE_RELEASE(m_pTargetedHandlers);
CC_SAFE_RELEASE(m_pStandardHandlers);
CC_SAFE_RELEASE(m_pHandlersToAdd);

ccCArrayFree(m_pHandlersToRemove);
m_pHandlersToRemove = NULL;
}

//
// handlers management
//
void CCTouchDispatcher::forceAddHandler(CCTouchHandler *pHandler, CCArray *pArray)
{
unsigned int u = 0;

CCObject* pObj = NULL;
//计算插入位置u
CCARRAY_FOREACH(pArray, pObj)
{
CCTouchHandler *h = (CCTouchHandler *)pObj;
if (h)
{
if (h->getPriority() < pHandler->getPriority())
{
++u;
}

if (h->getDelegate() == pHandler->getDelegate())//如果已存在容器,返回
{
CCAssert(0, "");
return;
}
}
}
//插入
pArray->insertObject(pHandler, u);
}

void CCTouchDispatcher::addStandardDelegate(CCTouchDelegate *pDelegate, int nPriority)
{
CCTouchHandler *pHandler = CCStandardTouchHandler::handlerWithDelegate(pDelegate, nPriority);
if (! m_bLocked)//如果没有被锁定
{
forceAddHandler(pHandler, m_pStandardHandlers);//注册到标准触摸事件的容器中
}
else
{
/* If pHandler is contained in m_pHandlersToRemove, if so remove it from m_pHandlersToRemove and return.
* Refer issue #752(cocos2d-x)
*/
if (ccCArrayContainsValue(m_pHandlersToRemove, pDelegate))//如果是属于待移除的委托,从容器中删除掉,并返回
{
ccCArrayRemoveValue(m_pHandlersToRemove, pDelegate);
return;
}
//增加到带分发的缓冲容器中
m_pHandlersToAdd->addObject(pHandler);
//用于通知系统已有触摸事件准备待分发
m_bToAdd = true;
}
}

void CCTouchDispatcher::addTargetedDelegate(CCTouchDelegate *pDelegate, int nPriority, bool bSwallowsTouches)
{
CCTouchHandler *pHandler = CCTargetedTouchHandler::handlerWithDelegate(pDelegate, nPriority, bSwallowsTouches);
if (! m_bLocked)//如果没有被锁定
{
forceAddHandler(pHandler, m_pTargetedHandlers);//注册到目标触摸事件的容器中
}
else
{
/* If pHandler is contained in m_pHandlersToRemove, if so remove it from m_pHandlersToRemove and return.
* Refer issue #752(cocos2d-x)
*/
if (ccCArrayContainsValue(m_pHandlersToRemove, pDelegate))//如果是属于待移除的委托,从容器中删除掉,并返回
{
ccCArrayRemoveValue(m_pHandlersToRemove, pDelegate);
return;
}
//增加到带分发的缓冲容器中
m_pHandlersToAdd->addObject(pHandler);
//用于通知系统已有触摸事件准备待分发
m_bToAdd = true;
}
}

void CCTouchDispatcher::forceRemoveDelegate(CCTouchDelegate *pDelegate)
{
CCTouchHandler *pHandler;

// XXX: remove it from both handlers ???

// remove handler from m_pStandardHandlers
//从标准触摸容器中移除
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pStandardHandlers, pObj)
{
pHandler = (CCTouchHandler*)pObj;
if (pHandler && pHandler->getDelegate() == pDelegate)//找到对应的委托
{
m_pStandardHandlers->removeObject(pHandler);//删除委托
break;
}
}

// remove handler from m_pTargetedHandlers
//从目标触摸容器中移除
CCARRAY_FOREACH(m_pTargetedHandlers, pObj)
{
pHandler = (CCTouchHandler*)pObj;
if (pHandler && pHandler->getDelegate() == pDelegate)//找到对应的委托
{
m_pTargetedHandlers->removeObject(pHandler);//删除委托
break;
}
}
}

void CCTouchDispatcher::removeDelegate(CCTouchDelegate *pDelegate)
{
if (pDelegate == NULL)//参数检查
{
return;
}

if (! m_bLocked)//如果没有被锁定
{
forceRemoveDelegate(pDelegate);
}
else
{
/* If pHandler is contained in m_pHandlersToAdd, if so remove it from m_pHandlersToAdd and return.
* Refer issue #752(cocos2d-x)
*/
CCTouchHandler *pHandler = findHandler(m_pHandlersToAdd, pDelegate);//如果是属于待分发的委托,从容器中删除掉,并返回
if (pHandler)
{
m_pHandlersToAdd->removeObject(pHandler);
return;
}
//增加到带移除的缓冲容器中
ccCArrayAppendValue(m_pHandlersToRemove, pDelegate);
//用于通知系统已有触摸事件准备待移除
m_bToRemove = true;
}
}

void CCTouchDispatcher::forceRemoveAllDelegates(void)
{
m_pStandardHandlers->removeAllObjects();//删除所有的标准触摸事件委托
m_pTargetedHandlers->removeAllObjects();//删除所有的目标触摸事件委托
}

void CCTouchDispatcher::removeAllDelegates(void)
{
if (! m_bLocked)//如果没有被锁定
{
forceRemoveAllDelegates();//删除标准触摸事件委托和目标触摸事件委托
}
else
{
m_bToQuit = true;//通知要临时取消触摸分发,即要移除掉所有标准触摸事件委托和目标触摸事件委托
}
}

CCTouchHandler* CCTouchDispatcher::findHandler(CCTouchDelegate *pDelegate)
{
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pTargetedHandlers, pObj)//遍历目标触摸事件容器
{
CCTouchHandler* pHandler = (CCTouchHandler*)pObj;
if (pHandler->getDelegate() == pDelegate)//找到对应的委托,返回它
{
return pHandler;
}
}

CCARRAY_FOREACH(m_pStandardHandlers, pObj)//遍历标准触摸事件容器
{
CCTouchHandler* pHandler = (CCTouchHandler*)pObj;
if (pHandler->getDelegate() == pDelegate)//找到对应的委托,返回它
{
return pHandler;
}
}

return NULL;
}

CCTouchHandler* CCTouchDispatcher::findHandler(CCArray* pArray, CCTouchDelegate *pDelegate)
{
CCAssert(pArray != NULL && pDelegate != NULL, "");

CCObject* pObj = NULL;
CCARRAY_FOREACH(pArray, pObj)//遍历指定的触摸事件容器
{
CCTouchHandler* pHandle = (CCTouchHandler*)pObj;
if (pHandle->getDelegate() == pDelegate)//找到对应的委托,返回它
{
return pHandle;
}
}

return NULL;
}

void CCTouchDispatcher::rearrangeHandlers(CCArray *pArray)
{
std::sort(pArray->data->arr, pArray->data->arr + pArray->data->num, less);//排序优先级
}

void CCTouchDispatcher::setPriority(int nPriority, CCTouchDelegate *pDelegate)
{
CCAssert(pDelegate != NULL, "");

CCTouchHandler *handler = NULL;

handler = this->findHandler(pDelegate);//找到对应的委托

CCAssert(handler != NULL, "");

if (handler->getPriority() != nPriority)//判断是否需要设置优先级
{
handler->setPriority(nPriority);//设置优先级
this->rearrangeHandlers(m_pTargetedHandlers);//设置完优先级后重新排序数组中的优先级
this->rearrangeHandlers(m_pStandardHandlers);//设置完优先级后重新排序数组中的优先级
}
}

//
// dispatch events
//
void CCTouchDispatcher::touches(CCSet *pTouches, CCEvent *pEvent, unsigned int uIndex)
{
CCAssert(uIndex >= 0 && uIndex < 4, "");//参数检查

CCSet *pMutableTouches;
m_bLocked = true;//处理分发事件时将其锁定,防止处理循环遍历时,容器被破坏

// optimization to prevent a mutable copy when it is not necessary
unsigned int uTargetedHandlersCount = m_pTargetedHandlers->count();//待处理的目标触摸事件数量
unsigned int uStandardHandlersCount = m_pStandardHandlers->count();//待处理的标准触摸事件数量
bool bNeedsMutableSet = (uTargetedHandlersCount && uStandardHandlersCount);//如果既要处理目标触摸事件也要处理标准触摸事件,则为true

pMutableTouches = (bNeedsMutableSet ? pTouches->mutableCopy() : pTouches);//如果bNeedsMutableSet,则将要处理的触摸点拷贝一份出来,否则则引用它

struct ccTouchHandlerHelperData sHelper = m_sHandlerHelperData[uIndex];//初始化操作触摸类别
//
// process the target handlers 1st
//
if (uTargetedHandlersCount > 0)//处理目标触摸事件
{
CCTouch *pTouch;
CCSetIterator setIter;
for (setIter = pTouches->begin(); setIter != pTouches->end(); ++setIter)//遍历触摸点
{
pTouch = (CCTouch *)(*setIter);

CCTargetedTouchHandler *pHandler = NULL;
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pTargetedHandlers, pObj)//遍历已被注册到目标触摸事件的容器
{
pHandler = (CCTargetedTouchHandler *)(pObj);//获取目标触摸句柄

if (! pHandler)//为空,跳出循环
{
break;
}

bool bClaimed = false;//初始化是否开始触摸处理
if (uIndex == CCTOUCHBEGAN)//触摸开始事件
{
bClaimed = pHandler->getDelegate()->ccTouchBegan(pTouch, pEvent);//处理完开始触摸事件后返回true,则继续处理其他事件,且如果设置吞噬的话,则吞噬优先级比它低的事件

if (bClaimed)//如果是声明处理完了触摸点
{
pHandler->getClaimedTouches()->addObject(pTouch);//将触摸点加入到声明触摸容器中
}
} else
if (pHandler->getClaimedTouches()->containsObject(pTouch))//如果该触摸点是被放到声明触摸容器中的,则继续处理其他事件
{
// moved ended canceled
bClaimed = true;

switch (sHelper.m_type)
{
case CCTOUCHMOVED://触摸移动事件
pHandler->getDelegate()->ccTouchMoved(pTouch, pEvent);
break;
case CCTOUCHENDED://触摸结束事件
pHandler->getDelegate()->ccTouchEnded(pTouch, pEvent);
pHandler->getClaimedTouches()->removeObject(pTouch);
break;
case CCTOUCHCANCELLED://触摸取消事件
pHandler->getDelegate()->ccTouchCancelled(pTouch, pEvent);
pHandler->getClaimedTouches()->removeObject(pTouch);
break;
}
}

if (bClaimed && pHandler->isSwallowsTouches())//处理吞噬事件
{
if (bNeedsMutableSet)//如果是既要处理目标触摸事件也要处理标准触摸事件
{
pMutableTouches->removeObject(pTouch);//移除触摸
}

break;//跳出,不继续分发执行其他触摸事件,即将触摸事件吞噬掉
}
}
}
}

//
// process standard handlers 2nd
//
if (uStandardHandlersCount > 0 && pMutableTouches->count() > 0)//处理标准触摸事件
{
CCStandardTouchHandler *pHandler = NULL;
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pStandardHandlers, pObj)//遍历已被注册到标准触摸事件的容器
{
pHandler = (CCStandardTouchHandler*)(pObj);//获取标准触摸句柄

if (! pHandler)//为空,跳出循环
{
break;
}

switch (sHelper.m_type)
{
case CCTOUCHBEGAN://触摸开始事件
pHandler->getDelegate()->ccTouchesBegan(pMutableTouches, pEvent);
break;
case CCTOUCHMOVED://触摸移动事件
pHandler->getDelegate()->ccTouchesMoved(pMutableTouches, pEvent);
break;
case CCTOUCHENDED://触摸结束事件
pHandler->getDelegate()->ccTouchesEnded(pMutableTouches, pEvent);
break;
case CCTOUCHCANCELLED://触摸取消事件
pHandler->getDelegate()->ccTouchesCancelled(pMutableTouches, pEvent);
break;
}
}
}

if (bNeedsMutableSet)//释放资源
{
pMutableTouches->release();
}

//
// Optimization. To prevent a [handlers copy] which is expensive
// the add/removes/quit is done after the iterations
//
m_bLocked = false;//执行完成触摸处理后解除锁定,处理待分发和待移除的触摸事件
if (m_bToRemove)//是否需要处理待移除的触摸事件
{
m_bToRemove = false;
for (unsigned int i = 0; i < m_pHandlersToRemove->num; ++i)//遍历待移除触摸事件的缓冲数组
{
forceRemoveDelegate((CCTouchDelegate*)m_pHandlersToRemove->arr[i]);//逐一移除触摸事件
}
ccCArrayRemoveAllValues(m_pHandlersToRemove);//清空缓冲数组
}

if (m_bToAdd)//是否需要处理待分发的触摸事件
{
m_bToAdd = false;
CCTouchHandler* pHandler = NULL;
CCObject* pObj = NULL;
CCARRAY_FOREACH(m_pHandlersToAdd, pObj)//遍历待分发触摸事件的缓冲数组
{
pHandler = (CCTouchHandler*)pObj;
if (! pHandler)
{
break;
}

if (dynamic_cast<CCTargetedTouchHandler*>(pHandler) != NULL)//如果是目标触摸事件的分发
{
forceAddHandler(pHandler, m_pTargetedHandlers);//加到目标触摸事件的容器中
}
else
{
forceAddHandler(pHandler, m_pStandardHandlers);//加到标准触摸事件的容器中
}
}

m_pHandlersToAdd->removeAllObjects();//清空缓冲数组
}

if (m_bToQuit)//如果需要取消触摸事件分发
{
m_bToQuit = false;
forceRemoveAllDelegates();//移除所有触摸事件委托
}
}

void CCTouchDispatcher::touchesBegan(CCSet *touches, CCEvent *pEvent)
{
if (m_bDispatchEvents)//如果是触摸分发事件
{
this->touches(touches, pEvent, CCTOUCHBEGAN);//触摸开始
}
}

void CCTouchDispatcher::touchesMoved(CCSet *touches, CCEvent *pEvent)
{
if (m_bDispatchEvents)//如果是触摸分发事件
{
this->touches(touches, pEvent, CCTOUCHMOVED);//触摸移动
}
}

void CCTouchDispatcher::touchesEnded(CCSet *touches, CCEvent *pEvent)
{
if (m_bDispatchEvents)//如果是触摸分发事件
{
this->touches(touches, pEvent, CCTOUCHENDED);//触摸结束
}
}

void CCTouchDispatcher::touchesCancelled(CCSet *touches, CCEvent *pEvent)
{
if (m_bDispatchEvents)//如果是触摸分发事件
{
this->touches(touches, pEvent, CCTOUCHCANCELLED);//触摸结束
}
}


所以要实现cocos2d-x的触摸事件,只要做两件事就可以了,继承触摸委托类CCTouchDelegate,重写它相应的方法;注册触摸事件到相应的触摸容器中;注册完后容器中相应的句柄会代用委托中相应的方法;最后在退出时从触摸容器中移除掉。下一篇文章将用使用CCLayer和CCMenu来实现以上过程。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: