cocos2d-x触摸事件详细分析
2014-05-25 17:04
309 查看
在cocos2d-x启动时会初始化CCEGLView(不同平台,都有自己的实现,由于自己是在win32平台下开发,所以这里的CCEGLView实现是win32下的)。
接下来看什么时候会触发这个事件。
触发时会按以下流程来完成:
1)在创建CCEGLView时会初始化窗口信息,包括事件的处理
综合上面也内容可以看出cocos2d-x在启动时会初始化导演,并设置CCEGLView,而CCEGLiew的父类CCEGLViewProtocol则定义了触摸的行为方法,所以在设置CCEGLView时就已经悄悄的把这些行为与导演绑定在一起了,而且初始化导演时也已经创建了能触摸分发事件的句柄。
接下来看触摸分发类的对这些方法的定义,这些定义是在它的父类中,即触摸事件委托类EGLTouchDelegate:
在cocos2d-x中,有两种触摸事件类型,分别是标准触摸事件和带目标触摸事件,这个两个事件在分发是分别存在各自的触摸句柄类的数组中。
触摸句柄:
所以要实现cocos2d-x的触摸事件,只要做两件事就可以了,继承触摸委托类CCTouchDelegate,重写它相应的方法;注册触摸事件到相应的触摸容器中;注册完后容器中相应的句柄会代用委托中相应的方法;最后在退出时从触摸容器中移除掉。下一篇文章将用使用CCLayer和CCMenu来实现以上过程。
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来实现以上过程。
相关文章推荐
- cocos2d-x源码分析-----触摸事件的实现
- Cocos2d-x学习笔记(五)CCLayer分析及输入事件处理(触摸、重力传感器、按键)
- cocos2d 触摸事件
- cocos2d - 触摸事件
- [ IOS-Cocos2d-x 游戏开发之一] -cocos2d-x触摸事件优先级的探究与实践
- 「cocos2d-x」瓦片地图学习之地图滚动及触摸事件处理
- Cocos2d 摸索[3]: 鼠标点击(手势触摸)事件
- input 输入框内的输入事件详细分析
- 触摸事件处理分析
- 在cocos2d上添加UIView,触摸事件往下传递
- cocos2d 触摸事件的传递
- Cocos2d-x Win32键盘模拟触摸事件
- 触摸事件分析
- cocos2d-x触摸事件优先级的探究与实践
- COCOS2d中添加UIButton不响应触摸事件---iOS开发之最灵异事件之2
- cocos2d-x 触摸事件处理机制
- cocos2d ccLayer响应触摸事件方法
- cocos2d开发之触摸事件
- cocos2d-x 2.X demo学习笔记 9 ----Touches 触摸事件 以及碰撞检测
- Cocos2d-x游戏开发之单击事件_锁定触摸区域外的界面