cocos2dx触屏事件详解
版本:2.x 平台iso 先看mian.m文件 //创建一个iso应用 int retVal = UIApplicationMain(argc,argv,nil,@"AppController"); iOS系统会调用AppController 的didFinishLaunchingWithOptions函数,里面做了一些创建界面的东西 该函数内部有如下代码; cocos2d::CCApplication::sharedApplication()->run(); 注:*.mm文件为object C与C++混编文件命名 AppController.mm文件上面对AppDelegate创建一个对象,AppDelegate继承于CCApplication,cocos2d::CCApplication::sharedApplication()取得的就是该对象 进入CCApplication::run()函数 int CCApplication::run() { if (applicationDidFinishLaunching()) { [[CCDirectorCaller sharedDirectorCaller] startMainLoop]; } return 0; } 进入 AppDelegate::applicationDidFinishLaunching 函数,省略部分代码bool AppDelegate::applicationDidFinishLaunching() { // initialize director CCDirector *pDirector = CCDirector::sharedDirector(); pDirector->setOpenGLView(CCEGLView::sharedOpenGLView()); 进入setOpenGLView函数,void CCDirector::setOpenGLView(CCEGLView *pobOpenGLView) { 。 。 。 m_pobOpenGLView->setTouchDelegate(m_pTouchDispatcher);//设置触摸代理 只是对CCEGLViewProtocol中EGLTouchDelegate* m_pDelegate; 变量初始化 m_pTouchDispatcher->setDispatchEvents(true);//设置接受派发事件 } } CCDirector::init() 已经对cocos2dx引擎用到的变量进行了一些初始化 m_pTouchDispatcher = new CCTouchDispatcher(); m_pTouchDispatcher->init(); 我们先回头看一下cocosdx是怎么从ios系统中取得触摸事件: 为了便于针对openGL ES的编程,苹果公司提供了派生于类UIView的类EAGLView来实现OpenGL的输出支持。 这样EAGLView.mm中得 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 就会接受到ios系统发送过来的触屏事件 里面分别调用了 cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesBegin(i,ids,xs,ys); cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesMove(i,ys); cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesEnd(i,ys); cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesCancel(i,ys); 进入CCEGLViewProtocol 的这几个函数,里面分别调用了 m_pDelegate->touchesBegan(&set,NULL); m_pDelegate->touchesMoved(&set,NULL); m_pDelegate->touchesEnded(&set,NULL); m_pDelegate->touchesCancelled(&set,NULL); 上面已经对m_pDelegate 进行了赋值m_pTouchDispatcher=newCCTouchDispatcher(); m_pobOpenGLView->setTouchDelegate(m_pTouchDispatcher);
这样CCTouchDispatcher 就能接受到ios系统发送过来的触屏事件了。 看一下 这几个函数m_bDispatchEvents 上面已经对其设置为 true 然后这几个函数都会调用该类的touches函数 void CCTouchDispatcher::touchesBegan(CCSet *touches,CCEvent *pEvent) { if (m_bDispatchEvents) { this->touches(touches,pEvent,CCTOUCHBEGAN); } }
void CCTouchDispatcher::touchesMoved(CCSet *touches,CCTOUCHMOVED); } }
void CCTouchDispatcher::touchesEnded(CCSet *touches,CCTOUCHENDED); } }
void CCTouchDispatcher::touchesCancelled(CCSet *touches,CCTOUCHCANCELLED); } } 我们来看下touches函数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);
pMutableTouches = (bNeedsMutableSet ? pTouches->mutableCopy() : pTouches);
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; //从CCTargetedTouchHandler的数组中取出单个CCTargetedTouchHandler对象 CCARRAY_FOREACH(m_pTargetedHandlers,pObj) { pHandler = (CCTargetedTouchHandler *)(pObj);
if (! pHandler) { break; }
bool bClaimed = false; if (uIndex == CCTOUCHBEGAN) { //这里调用CCTargetedTouchHandler对象的ccTouchBegin方法,我们知道cocos2dx中layer为cocos2dx中接受触屏事件的最小单位 bClaimed = pHandler->getDelegate()->ccTouchBegan(pTouch,pEvent); //如果ccTouchBegin 方法返回true 会把这个CCTargetedTouchHandler对象 加入到 处理 move end canceled 的数组中 //意思就是 如果ccTouchBegin 方法返回true 该CCTargetedTouchHandler对象 才会继续接受到move end canceled 这三个事件 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; } } //如果有CCTargetedTouchHandler对象 接受到这个触摸事件了 如果设置为吞并事件 不向下传递了 这里就会把 触屏事件删除 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(); } } 现在我们已经了解了 触屏事件的调用流程,我们来看一下 上面的m_pTargetedHandlers 变量是怎么添加对象的先来看一下 CCLayer函数中得 setTouchEnabled函数 有如下代码 void CCLayer::setTouchEnabled(bool enabled) if (enabled) {//ture 注册 this->registerWithTouchDispatcher(); } else { // 传进来的是false删除 CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this); } 看下这个函数void CCLayer::registerWithTouchDispatcher() { CCTouchDispatcher* pDispatcher = CCDirector::sharedDirector()->getTouchDispatcher();
// Using LuaBindings 用于lua的 if (m_pScriptTouchHandlerEntry) { if (m_pScriptTouchHandlerEntry->isMultiTouches()) { pDispatcher->addStandardDelegate(this,0); LUALOG("[LUA] Add multi-touches event handler: %d",m_pScriptTouchHandlerEntry->getHandler()); } else { pDispatcher->addTargetedDelegate(this, m_pScriptTouchHandlerEntry->getPriority(), m_pScriptTouchHandlerEntry->getSwallowsTouches()); LUALOG("[LUA] Add touch event handler: %d",m_pScriptTouchHandlerEntry->getHandler()); } } else { if( m_eTouchMode == kCCTouchesAllAtOnce ) { pDispatcher->addStandardDelegate(this,0); } else { pDispatcher->addTargetedDelegate(this,m_nTouchPriority,true);//把当前layer或layer的子类加入//触摸优先级//接受到触摸事件是否吞并 不向该优先级以下 传递 } } } 看下addTargetedDelegate函数m_pTargetedHandlers 就是我们上文中 touchs函数中CCTouchHandler* 的数组 void CCTouchDispatcher::addTargetedDelegate(CCTouchDelegate *pDelegate,int nPriority,bool bSwallowsTouches) { CCTouchHandler *pHandler = CCTargetedTouchHandler::handlerWithDelegate(pDelegate,nPriority,bSwallowsTouches); if (! m_bLocked) { forceAddHandler(pHandler,m_pTargetedHandlers); } 然后再看下forceAddHandler函数,该函数添加之前需要遍历一遍数组,把当前加入的CCTouchHandler* 按优先级加入到已有的CCTouchHandler*数组中从下面的代码中 我们知道 数组的排序是按 优先级 从小到大排列的 也就是说 设置的优先级 越小,就会最优先接受到触屏事件 void CCTouchDispatcher::forceAddHandler(CCTouchHandler *pHandler,CCArray *pArray) { unsigned int u = 0; CCObject* pObj = NULL; //遍历数组 CCARRAY_FOREACH(pArray,pObj) { CCTouchHandler *h = (CCTouchHandler *)pObj; if (h) {//比较优先级 设置插入的位置 if (h->getPriority() < pHandler->getPriority()) { ++u; } if (h->getDelegate() == pHandler->getDelegate()) { CCAssert(0, ""); return; } } } //向该数组中 加入该CCTouchHandler*pHandler pArray->insertObject(pHandler,u); }
现在触摸事件的流程,我们已经知道了,现在来实现我们自己的触摸函数 首先我们要继承CCLayer函数,重写接受触摸事件的个函数 class UILayer : public CCLayer { public: UILayer(); ~UILayer(); public: virtual bool init(); virtual void onEnter(); virtual void onExit(); virtual void registerWithTouchDispatcher(); virtual bool ccTouchBegan(CCTouch* touch,CCEvent* event); virtual void ccTouchEnded(CCTouch* touch,CCEvent* event); virtual void ccTouchCancelled(CCTouch* touch,CCEvent* event); virtual void ccTouchMoved(CCTouch* touch,CCEvent* event); CREATE_FUNC(UILayer); }; UILayer::UILayer() { }
UILayer::~UILayer() { }
bool UILayer::init() { if ( !CCLayer::init() ) { return false; } return true; }
void UILayer::onEnter() { CCLayer::onEnter(); setTouchEnabled(true); }
void UILayer::onExit() { CCLayer::onExit(); }
void UILayer::registerWithTouchDispatcher() { CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,ROR::TOUCH_UI_PRIORITY,true);//默认吞噬触摸事件 }
bool UILayer::ccTouchBegan(CCTouch* touch,CCEvent* event) { CCLOG("ccTouchBegan"); return true; }
void UILayer::ccTouchEnded(CCTouch* touch,CCEvent* event) { CCLOG("ccTouchEnded"); }
void UILayer::ccTouchCancelled(CCTouch* touch,CCEvent* event) { CCLOG("ccTouchCancelled"); }
void UILayer::ccTouchMoved(CCTouch* touch,CCEvent* event) { CCLOG("ccTouchMoved"); } OK,触摸事件已经实现了,可以根据自己的需要,写一些逻辑了。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |