这里是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()取得的就是该对象
static AppDelegate s_sharedApplication;
进入 CCApplication::run()函数
int CCApplication::run()
{
if (applicationDidFinishLaunching())
{
[[CCDirectorCallersharedDirectorCaller] 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)touchesBeganNSSet *)touches withEventUIEvent *)event
- (void)touchesMovedNSSet *)touches withEventUIEvent *)event
- (void)touchesEndedNSSet *)touches withEventUIEvent *)event
- (void)touchesCancelledNSSet *)touches withEventUIEvent *)event
就会接受到ios系统发送过来的触屏事件
里面分别调用了
cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesBegin(i, ids, xs, ys);
cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesMove(i, ids, xs, ys);
cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesEnd(i, ids, xs, ys);
cocos2d::CCEGLView::sharedOpenGLView()->handleTouchesCancel(i, ids, xs, 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 = new CCTouchDispatcher();
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,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);
}
}我们来看下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);
structccTouchHandlerHelperData 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;
caseCCTOUCHCANCELLED:
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 (unsignedint i = 0; i < m_pHandlersToRemove->num; ++i)
{
forceRemoveDelegate((CCTouchDelegate*)m_pHandlersToRemove->arr);
}
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 : publicCCLayer
{
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:nEnter()
{
CCLayer:nEnter();
setTouchEnabled(true);
}
void UILayer:nExit()
{
CCLayer:nExit();
}
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”);